1. 程式人生 > >BZOJ1043:[HAOI2008]下落的圓盤——題解

BZOJ1043:[HAOI2008]下落的圓盤——題解

med csdn die def tac truct online name urn

http://www.lydsy.com/JudgeOnline/problem.php?id=1043

Description

  有n個圓盤從天而降,後面落下的可以蓋住前面的。求最後形成的封閉區域的周長。看下面這副圖, 所有的紅
色線條的總長度即為所求. 技術分享圖片

Input

  第一行為1個整數n,N<=1000
接下來n行每行3個實數,ri,xi,yi,表示下落時第i個圓盤的半徑和圓心坐標.

Output

  最後的周長,保留三位小數

Sample Input

2
1 0 0
1 1 0

Sample Output

10.472

————————————————————————————————

代碼借(抄)鑒(襲)於:http://blog.csdn.net/Vmurder/article/details/46564199

我們可以用弧度制來表示當前圓被覆蓋的部分。

基本上高中數學知識即可解決,這裏配一張圖:

(圖片被割了,所以等有時間再補……)

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<stack>
#include<cmath>
#include<algorithm>
using
namespace std; typedef double dl; const int N=1001; const dl poi=acos(-1.0); struct circle{ dl r; dl x; dl y; }p[N]; struct line{ dl l; dl r; }seg[N][2*N]; int n,cnt[N]; bool die[N]; inline dl dis(circle a,circle b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } inline
int inc(circle a,circle b){ dl d=dis(a,b); if(a.r+b.r<d)return 0;//兩圓相離 if(a.r>b.r&&a.r-b.r>d)return -1;//a覆蓋b if(b.r>a.r&&b.r-a.r>d)return 0;//b覆蓋a return 1;//兩圓相交 } inline void getinc(circle a,circle b,dl &i,dl &j){//a覆蓋b double alpha=atan2((b.y-a.y),(b.x-a.x)); dl d=dis(a,b); double beta=acos((b.r*b.r+d*d-a.r*a.r)/(2*b.r*d)); i=alpha-beta; j=alpha+beta; return; } inline bool gai(line &a){ if(a.r>poi){ a.r-=2*poi; return 1; } if(a.l<-poi){ a.l+=2*poi; return 1; } return 0; } bool cmp(line a,line b){ return a.l<b.l; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lf%lf%lf",&p[i].r,&p[i].x,&p[i].y); for(int j=1;j<i;j++){ if(die[j])continue; int k=inc(p[i],p[j]); if(!k)continue; if(k==-1){ die[j]=1; continue; } cnt[j]++; getinc(p[i],p[j],seg[j][cnt[j]].l,seg[j][cnt[j]].r); if(gai(seg[j][cnt[j]])){ cnt[j]++; seg[j][cnt[j]].l=-poi; seg[j][cnt[j]].r=seg[j][cnt[j]-1].r; seg[j][cnt[j]-1].r=poi; } } } dl ans=0; for(int i=1;i<=n;i++){ if(!die[i]){ dl re=2*poi,L,R; if(cnt[i]){ sort(seg[i]+1,seg[i]+cnt[i]+1,cmp); L=seg[i][1].l;R=seg[i][1].r; for(int j=2;j<=cnt[i];j++){ if(seg[i][j].l>R){ re-=R-L; L=seg[i][j].l; R=seg[i][j].r; }else{ R=max(R,seg[i][j].r); } } re-=R-L; } ans+=re*p[i].r; } } printf("%.3lf\n",ans); return 0; }

BZOJ1043:[HAOI2008]下落的圓盤——題解