对于每个园,求它对答案的贡献 1.若被后面的园覆盖,则为0 2.若和后面的园相交,用余弦定理和atan2函数求出每个圆和其他圆相交的弧度范围(l,r),用线段覆盖求出最后剩下的弧度,从而得出贡献。 atan2(y,x)返回向量(x,y)与x轴的夹角,范围-180~180 注意弧度变为负数时要进行修正 代码参考的这里,求弧度的公式换了下而已 传送门
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<ctime> #include<queue> #include<cmath> #include<algorithm> #define ll long long #define pi acos(-1) using namespace std; int n,top; double ans; double x[1005],y[1005],r[1005]; struct line{double l,r;}q[1005]; bool operator<(line a,line b) { return a.l<b.l; } inline double dis(int a,int b) { return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b])); } bool conta(int a,int b) { if(r[a]>=r[b]+dis(a,b))return 1; return 0; } void inter(int a,int b) { double d,t,st,l; d=dis(a,b); st=atan2((y[b]-y[a]),(x[b]-x[a])); l=acos((r[a]*r[a]+d*d-r[b]*r[b])/(2*r[a]*d)); q[++top]=(line){(st-l),(st+l)}; } double cal(int x) { for(int i=x+1;i<=n;i++) if(conta(i,x))return 0; top=0; for(int i=x+1;i<=n;i++) { if(!conta(x,i)&&r[x]+r[i]>=dis(x,i))inter(x,i); } double tmp=0,now=0; for(int i=1;i<=top;i++) { if(q[i].l<0)q[i].l+=2*pi; if(q[i].r<0)q[i].r+=2*pi; if(q[i].l>q[i].r) { q[++top]=(line){0,q[i].r}; q[i].r=2*pi; } } sort(q+1,q+top+1); for(int i=1;i<=top;i++) if(q[i].l>now) { tmp+=q[i].l-now; now=q[i].r; } else now=max(now,q[i].r); tmp+=2*pi-now; return r[x]*tmp; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&r[i],&x[i],&y[i]); for(int i=1;i<=n;i++) ans+=cal(i); printf("%.3lf\n",ans); return 0; }