题意:就是让你求图中红色边的长度,不会出现切割面积覆盖原零件面积和两个切割面积交叉的情况。
做法:一开始直接用两圆相交求交点的几何模板构造了算法,没想到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;
}