Description
有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红
色线条的总长度即为所求.
Input
第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.
Output
最后的周长,保留三位小数
对每个圆,若没被后面的圆完全覆盖,就统计后面的圆覆盖的圆周长度,具体实现可以求出圆周上每个被覆盖区间并取并
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; typedef double ld; int n; const ld pi=acos(-1.l),_2pi=pi*2; struct itv{ld l,r;}; bool operator<(itv x,itv y){return x.l<y.l;} int ip=0; ld ans=0; void maxs(ld&a,ld b){if(a<b)a=b;} itv is[2007]; struct cir{ ld x,y,r; void init(){ scanf("%lf%lf%lf",&r,&x,&y); } bool in(cir w){ ld a=x-w.x,b=y-w.y; return sqrt(a*a+b*b)+r-1e-8<w.r; } bool cross(cir w){ ld a=x-w.x,b=y-w.y; ld c=sqrt(a*a+b*b); return c<r+w.r-1e-8&&c>fabs(r-w.r)+1e-8; } ld fix(ld x){ while(x<0)x+=_2pi; while(x>_2pi)x-=_2pi; return x; } void cal(cir w){ ld xd=w.x-x,yd=w.y-y,d=sqrt(xd*xd+yd*yd); ld a=atan2(yd,xd); ld b=acos((r*r+d*d-w.r*w.r)/(2*r*d)); ld l=fix(a-b),r=fix(a+b); if(l<r)is[ip++]=(itv){l,r}; else is[ip++]=(itv){0,r},is[ip++]=(itv){l,_2pi}; } void get(){ std::sort(is,is+ip); ld L,R,s=_2pi; for(int i=0,j=0;i<ip;i=j){ L=is[i].l;R=is[i].r; while(j<ip&&is[j].l<=R)maxs(R,is[j++].r); s-=R-L; } ans+=s*r; } }cs[1007]; int main(){ scanf("%d",&n); for(int i=0;i<n;++i)cs[i].init(); for(int i=0;i<n;++i){ ip=0; for(int j=i+1;j<n;++j)if(cs[i].in(cs[j]))goto out; for(int j=i+1;j<n;++j)if(cs[i].cross(cs[j]))cs[i].cal(cs[j]); cs[i].get(); out:; } printf("%.3f",ans); return 0; }