Problem 1047 : Crop Circle
問題概要
日本語なので本文参照
(http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=1047)
解法
幾何+区間を覆う長さ問題。
一つの円について、他の円1,2…によって隠される部分を[a1,b1],[a2,b2]...とすれば、
(ただしai,biは偏角とする)
区間の全ての和集合が隠される部分全体で、これは数直線上に区間が沢山あったとき、和集合の長さを求める問題そのものである。
二円の交点が求まったとき、aiに微小な量を足して、弧がどちら側にあるのかを判定している。
(a+epsが隠れているなら[a,b]が隠れる区間で、a+epsが隠れていないなら、
[-PI,a]と[b,PI]が隠れる区間になる)
このepsは1e-9だとWAで、1e-5にしたら通った。
二円の交点はがんばって求める。
ソースコード
int n; P c[100]; double r[100]; pair<double,double> crossptCC(P a,double r,P b,double s){ double d=abs(a-b),e=(d*d+r*r-s*s)/2/d,h=sqrt(r*r-e*e); P dir=(b-a)*(1/d),x=dir*e+dir*P(0,1)*h,y=dir*e-dir*P(0,1)*h; return mp(arg(x),arg(y)); } int main(){ while(scanf("%d",&n),n){ rep(i,n)scanf("%lf%lf%lf",&c[i].real(),&c[i].imag(),r+i); double ans=0; rep(i,n){ map<double,int> M; int cnt=0; double p,s=0; M[-PI]=0; M[PI]=0; rep(j,n)if(i!=j){ double d=abs(c[i]-c[j]); if(d>r[i]+r[j]-EPS)continue; if(d<abs(r[i]-r[j])+EPS){ if(r[i]>r[j])continue; goto END; } pair<double,double> crs=crossptCC(c[i],r[i],c[j],r[j]); double a=crs.first,b=crs.second; if(a>b)swap(a,b); if(abs(c[i]+r[i]*P(cos(a+1e-5),sin(a+1e-5))-c[j])<r[j]+EPS)M[a]++,M[b]--; else{ M[-PI]++; M[a]--; M[b]++; M[PI]--; } } fr(j,M){ if(cnt>0)s+=j->first-p; cnt+=j->second; p=j->first; } ans+=(2*PI-s)*r[i]; END:; } printf("%.9f\n",ans); } return 0; }