[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
枚举每一个圆,看它有多少没有被覆盖。
每一个圆的极角可以拉直成一个长为2×pi的线段
然后套用数学公式,算出一个圆覆盖的范围
要注意讨论极角小于0的情况
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct ZYYS 8 { 9 double l,r; 10 }a[5001]; 11 double pi=acos(-1.0); 12 int n; 13 double x[1001],y[1001],r[1001],ans; 14 bool cmp(ZYYS a,ZYYS b) 15 { 16 return a.l<b.l; 17 } 18 double dist(int i,int j) 19 { 20 return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); 21 } 22 bool contain(int i,int j) 23 { 24 if (r[i]-r[j]>=dist(i,j)) return 1; 25 return 0; 26 } 27 double cal(int o) 28 {int i; 29 int cnt=0; 30 for (i=o+1;i<=n;i++) 31 if (contain(i,o)) return 0; 32 for (i=o+1;i<=n;i++) 33 { 34 if (contain(o,i)||dist(o,i)>=r[i]+r[o]) continue; 35 double d=dist(o,i); 36 double xt=acos((-r[i]*r[i]+r[o]*r[o]+d*d)/(2.0*d*r[o])); 37 double aef=atan2(y[i]-y[o],x[i]-x[o]); 38 a[++cnt]=(ZYYS){aef-xt,aef+xt}; 39 if (a[cnt].l<0) a[cnt].l+=2*pi; 40 if (a[cnt].r<0) a[cnt].r+=2*pi; 41 if (a[cnt].l>a[cnt].r) 42 { 43 double p=a[cnt].l; 44 a[cnt].l=0; 45 a[++cnt].l=p;a[cnt].r=2*pi; 46 } 47 } 48 sort(a+1,a+cnt+1,cmp); 49 double res=0,now=0; 50 for (i=1;i<=cnt;i++) 51 { 52 if (a[i].l>now) res+=a[i].l-now,now=a[i].r; 53 now=max(now,a[i].r); 54 } 55 res+=2*pi-now; 56 return res*r[o]; 57 } 58 int main() 59 {int i; 60 cin>>n; 61 for (i=1;i<=n;i++) 62 { 63 scanf("%lf%lf%lf",&r[i],&x[i],&y[i]); 64 } 65 for (i=1;i<=n-1;i++) 66 ans+=cal(i); 67 ans+=2*pi*r[n]; 68 printf("%.3lf\n",ans); 69 }