[HDU](6354)Everything Has Changed ---- 余弦定理+计算几何

题目链接

题意:就是让你求图中红色边的长度,不会出现切割面积覆盖原零件面积和两个切割面积交叉的情况。

做法:一开始直接用两圆相交求交点的几何模板构造了算法,没想到WA到哭QAQ

到最后看了杜教的B站讲解才知道自己好懵逼,直接饶了原路,知道三边是可以用余弦定理的啊!!

这样的话就不用板子了,估计自己一直wa,是计算太多,导致精度缺失了吧……

做法的话,内切和外切、相离就不用说啦

就说说相交:我们把圆心为(0,0)的圆称为大圆,半径为R,其他称为小圆,半径为r

一、两圆心的直线与R的夹角 (a2/2)为锐角时

我们可以用余弦定理,求得角a2/2,以及角a1/2,这样就可求出弧长c2,c1

用大圆的周长l1    所求的边长= l1-c1+c2

二、两圆心的直线与R的夹角 (a2/2)为钝角时

我们可以用余弦定理,求得角a2,以及角a1/2,这时我们相求弧长c2(即小圆对应的弧长),就应该是用角度π-a2

这样用角a1和2*(π-a2)就可以求弧长c1,c2

大圆的周长l1,小圆的周长l2,所求的边长 = l - c1 + (l2-c2)

以上~

AC代码:

#include<bits/stdc++.h>
using namespace std;
const double PI = 4*atan2(1.0,1.0);
struct PPoint
{
    double x,y;
};
double len(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
struct Circle
{
    double x,y,r;
};
int main()
{
    #ifdef LOCAL_FILE
    freopen("in.txt","r",stdin);
    #endif // LOCAL_FILE
    int t;
    scanf("%d",&t);
    while(t--)
    {
        Circle cc[105];
        double R;
        int m;
        scanf("%d %lf",&m,&R);
        for(int i=0;i<m;i++)
            scanf("%lf %lf %lf",&cc[i].x,&cc[i].y,&cc[i].r);
        double cir1 = 2*PI*R;
        double ans = cir1;
        for(int i=0;i<m;i++)
        {
            double d1 = len(cc[i].x,cc[i].y,0,0);
            double cir2 = 2*PI*cc[i].r;
            if(d1+cc[i].r == R)
            {
                ans+=cir2;
            }
            else if(d1 == cc[i].r+R)
                continue;
            else if(d1+cc[i].r<R)
                continue;
            else
            {
                double a1 = acos((R*R+d1*d1-cc[i].r*cc[i].r)/(2*d1*R));
                double a2 = acos((cc[i].r*cc[i].r+d1*d1-R*R)/(2*d1*cc[i].r));
                double c1 = 2*a1*R;
                double c2;
                if(a2<=PI/2)
                {
                    c2 = 2*a2*cc[i].r;
                    ans+=c2;
                    ans-=c1;
                }
                else if(a2>PI/2)
                {
                    a2 = PI-a2;
                    c2 = 2*a2*cc[i].r;
                    ans = ans+(cir2-c2);
                    ans-=c1;
                }
            }
        }
        printf("%.20f\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值