bzoj1043 [HAOI2008]下落的圆盘
Description
有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红色线条的总长度即为所求.
Input
第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.
Output
最后的周长,保留三位小数
Sample Input
2
1 0 0
1 1 0
1 0 0
1 1 0
Sample Output
10.472
正解:计算几何。
枚举每一个圆,看它有多少没有被覆盖。
具体来说,就是再枚举与它相交且在它上面的圆,算出这个圆的覆盖区间,然后求出所有区间的总覆盖长度即可。
对于一个圆,可以求出圆心距的那条线的极角,然后用余弦定理求出这条直线与交点和圆心的直线的夹角,即可得夹角区间。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define N (2005) 6 7 using namespace std; 8 9 const double pi=acos(-1.0); 10 11 struct point{ double r,x,y; }p[N]; 12 struct data{ double l,r; }st[N]; 13 14 double ans; 15 int n,top; 16 17 il int cmp(const data &a,const data &b){ return a.l<b.l; } 18 19 il double dis(RG int i,RG int j){ 20 return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)); 21 } 22 23 il int contain(RG int i,RG int j){ return p[j].r-p[i].r>=dis(i,j); } 24 25 il double calc(RG int id){ 26 for (RG int i=id+1;i<=n;++i) if (contain(id,i)) return 0; 27 for (RG int i=id+1;i<=n;++i){ 28 RG double d=dis(i,id); if (contain(i,id) || p[i].r+p[id].r<=d) continue; 29 RG double t=acos((d*d+p[id].r*p[id].r-p[i].r*p[i].r)/(2*d*p[id].r)); 30 RG double base=atan2(p[i].y-p[id].y,p[i].x-p[id].x); 31 st[++top]=(data){base-t,base+t}; 32 if (st[top].l<0) st[top].l+=2*pi; if (st[top].r<0) st[top].r+=2*pi; 33 if (st[top].l>st[top].r) st[top+1]=(data){0,st[top].r},st[top++].r=2*pi; 34 } 35 sort(st+1,st+top+1,cmp); RG double now=0,res=0; 36 for (RG int i=1;i<=top;++i){ 37 if (now<st[i].l) res+=st[i].l-now,now=st[i].r; 38 else now=max(now,st[i].r); 39 } 40 res+=2*pi-now,top=0; return res*p[id].r; 41 } 42 43 int main(){ 44 #ifndef ONLINE_JUDGE 45 freopen("circle.in","r",stdin); 46 freopen("circle.out","w",stdout); 47 #endif 48 cin>>n; 49 for (RG int i=1;i<=n;++i) scanf("%lf%lf%lf",&p[i].r,&p[i].x,&p[i].y); 50 for (RG int i=1;i<=n;++i) ans+=calc(i); printf("%0.3lf\n",ans); return 0; 51 }