bzoj1043 [HAOI2008]下落的圓盤
阿新 • • 發佈:2017-12-31
tdi cmp esp ++ 交點 namespace fin bzoj1043 clu
1 0 0
1 1 0
Description
有n個圓盤從天而降,後面落下的可以蓋住前面的。求最後形成的封閉區域的周長。看下面這副圖, 所有的紅色線條的總長度即為所求.
Input
第一行為1個整數n,N<=1000
接下來n行每行3個實數,ri,xi,yi,表示下落時第i個圓盤的半徑和圓心坐標.
Output
最後的周長,保留三位小數
Sample Input
21 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 structdata{ 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 inti,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 }
bzoj1043 [HAOI2008]下落的圓盤