首先考虑两个圆覆盖的情况,我们可以求出圆心与交点连线 $A$ 的极角
具体就是求出两圆心连线 $B$ 极角加上余弦定理加反余弦求出 $A,B$ 之间夹角 ,然后覆盖了多少就可以得出
但是多个圆覆盖会重复算,所以离线枚举后面的圆,然后把覆盖的区间按极角排序做一遍类似线段覆盖的操作就行了
区间覆盖的时候注意极角可以会算出负数和大于 $2pi$ 的情况
思路倒挺简单,计算几何实现起来反正就是一堆细节
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; typedef double db; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const db pi=acos(-1.0),pi2=pi*2,eps=1e-12; const int N=4007; int n; inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; } struct Poi { db x,y; Poi (db a=0,db b=0) { x=a,y=b; } inline Poi operator - (const Poi &tmp) const { return Poi(x-tmp.x,y-tmp.y); } }; inline db Len(Poi A) { return sqrt(A.x*A.x+A.y*A.y); } inline db angle(Poi A) { return atan2(A.y,A.x); } struct Circ { Poi O; db r; Circ (Poi a=Poi(0,0),db b=0) { O=a,r=b; } }C[N]; struct dat { db ang; int type; dat (db a=0,int b=0) { ang=a,type=b; } inline bool operator < (const dat &tmp) const { return ang<tmp.ang; } }D[N]; db work(int p) { db res=0; int tot=0,cnt=0; for(int i=p+1;i<=n;i++) { db dis=Len(C[i].O-C[p].O); if( C[p].r+dis<=C[i].r ) return 0;//p被完全覆盖 if( dis>=C[p].r+C[i].r || C[i].r+dis<=C[p].r ) continue;//p没被覆盖,记得可能 i 在 p 里面 db alp=acos( (dis*dis+C[p].r*C[p].r-C[i].r*C[i].r)/(2*dis*C[p].r) ),k=angle(C[i].O-C[p].O); db l=k-alp,r=k+alp;//两个交点的极角 if(dcmp(l)<0&&dcmp(r)<0) { D[++tot]=dat(l+pi2,1); D[++tot]=dat(r+pi2,-1); continue; } if(dcmp(l)>=0&&r<=pi2) { D[++tot]=dat(l,1); D[++tot]=dat(r,-1); continue; } if(dcmp(l)<0&&dcmp(r)>=0) { D[++tot]=dat(l+pi2,1); D[++tot]=dat(pi2,-1); D[++tot]=dat(0,1); D[++tot]=dat(r,-1); } if(dcmp(l)>=0&&r>pi2) { D[++tot]=dat(0,1); D[++tot]=dat(r-pi2,-1); D[++tot]=dat(l,1); D[++tot]=dat(pi2,-1); } } sort(D+1,D+tot+1); for(int i=1;i<=tot;i++) { if(D[i].type==1&&!cnt) res+=D[i].ang-D[i-1].ang;//线段覆盖 cnt+=D[i].type; } res+=pi2-D[tot].ang; return C[p].r*res; } int main() { n=read(); db a,b,c,ans=0; for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&a,&b,&c); C[i]=Circ( Poi(b,c) , a ); } for(int i=1;i<=n;i++) ans+=work(i); printf("%.3f ",ans); return 0; }