ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

  有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红
色线条的总长度即为所求. 

Input

  第一行为1个整数n,N<=1000
接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标.

Output

  最后的周长,保留三位小数

对每个圆,若没被后面的圆完全覆盖,就统计后面的圆覆盖的圆周长度,具体实现可以求出圆周上每个被覆盖区间并取并
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef double ld;
int n;
const ld pi=acos(-1.l),_2pi=pi*2;
struct itv{ld l,r;};
bool operator<(itv x,itv y){return x.l<y.l;}
int ip=0;
ld ans=0;
void maxs(ld&a,ld b){if(a<b)a=b;}
itv is[2007];
struct cir{
    ld x,y,r;
    void init(){
        scanf("%lf%lf%lf",&r,&x,&y);
    }
    bool in(cir w){
        ld a=x-w.x,b=y-w.y;
        return sqrt(a*a+b*b)+r-1e-8<w.r;
    }
    bool cross(cir w){
        ld a=x-w.x,b=y-w.y;
        ld c=sqrt(a*a+b*b);
        return c<r+w.r-1e-8&&c>fabs(r-w.r)+1e-8;
    }
    ld fix(ld x){
        while(x<0)x+=_2pi;
        while(x>_2pi)x-=_2pi;
        return x;
    }
    void cal(cir w){
        ld xd=w.x-x,yd=w.y-y,d=sqrt(xd*xd+yd*yd);
        ld a=atan2(yd,xd);
        ld b=acos((r*r+d*d-w.r*w.r)/(2*r*d));
        ld l=fix(a-b),r=fix(a+b);
        if(l<r)is[ip++]=(itv){l,r};
        else is[ip++]=(itv){0,r},is[ip++]=(itv){l,_2pi};
    }
    void get(){
        std::sort(is,is+ip);
        ld L,R,s=_2pi;
        for(int i=0,j=0;i<ip;i=j){
            L=is[i].l;R=is[i].r;
            while(j<ip&&is[j].l<=R)maxs(R,is[j++].r);
            s-=R-L;
        }
        ans+=s*r;
    }
}cs[1007];
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;++i)cs[i].init();
    for(int i=0;i<n;++i){
        ip=0;
        for(int j=i+1;j<n;++j)if(cs[i].in(cs[j]))goto out;
        for(int j=i+1;j<n;++j)if(cs[i].cross(cs[j]))cs[i].cal(cs[j]);
        cs[i].get();
        out:;
    }
    printf("%.3f",ans);
    return 0;
}

 

posted on 2016-12-08 21:33  nul  阅读(206)  评论(0编辑  收藏  举报