zoukankan      html  css  js  c++  java
  • P2510 [HAOI2008]下落的圆盘

    传送门

    首先考虑两个圆覆盖的情况,我们可以求出圆心与交点连线 $A$ 的极角

    具体就是求出两圆心连线 $B$ 极角加上余弦定理加反余弦求出 $A,B$ 之间夹角 ,然后覆盖了多少就可以得出

    但是多个圆覆盖会重复算,所以离线枚举后面的圆,然后把覆盖的区间按极角排序做一遍类似线段覆盖的操作就行了

    区间覆盖的时候注意极角可以会算出负数和大于 $2pi$ 的情况

    思路倒挺简单,计算几何实现起来反正就是一堆细节

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef double db;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const db pi=acos(-1.0),pi2=pi*2,eps=1e-12;
    const int N=4007;
    int n;
    inline int dcmp(db x) { if(fabs(x)<eps) return 0; return x<0 ? -1 : 1; }
    struct Poi {
        db x,y;
        Poi (db a=0,db b=0) { x=a,y=b; }
        inline Poi operator - (const Poi &tmp) const {
            return Poi(x-tmp.x,y-tmp.y);
        }
    };
    inline db Len(Poi A) { return sqrt(A.x*A.x+A.y*A.y); }
    inline db angle(Poi A) { return atan2(A.y,A.x); }
    struct Circ {
        Poi O; db r;
        Circ (Poi a=Poi(0,0),db b=0) { O=a,r=b; }
    }C[N];
    struct dat {
        db ang; int type;
        dat (db a=0,int b=0) { ang=a,type=b; }
        inline bool operator < (const dat &tmp) const {
            return ang<tmp.ang;
        }
    }D[N];
    db work(int p)
    {
        db res=0; int tot=0,cnt=0;
        for(int i=p+1;i<=n;i++)
        {
            db dis=Len(C[i].O-C[p].O);
            if( C[p].r+dis<=C[i].r ) return 0;//p被完全覆盖
            if( dis>=C[p].r+C[i].r || C[i].r+dis<=C[p].r ) continue;//p没被覆盖,记得可能 i 在 p 里面
            db alp=acos( (dis*dis+C[p].r*C[p].r-C[i].r*C[i].r)/(2*dis*C[p].r) ),k=angle(C[i].O-C[p].O);
            db l=k-alp,r=k+alp;//两个交点的极角
            if(dcmp(l)<0&&dcmp(r)<0) { D[++tot]=dat(l+pi2,1); D[++tot]=dat(r+pi2,-1); continue; }
            if(dcmp(l)>=0&&r<=pi2) { D[++tot]=dat(l,1); D[++tot]=dat(r,-1); continue; }
            if(dcmp(l)<0&&dcmp(r)>=0)
            {
                D[++tot]=dat(l+pi2,1); D[++tot]=dat(pi2,-1);
                D[++tot]=dat(0,1); D[++tot]=dat(r,-1);
            }
            if(dcmp(l)>=0&&r>pi2)
            {
                D[++tot]=dat(0,1); D[++tot]=dat(r-pi2,-1);
                D[++tot]=dat(l,1); D[++tot]=dat(pi2,-1);
            }
        }
        sort(D+1,D+tot+1);
        for(int i=1;i<=tot;i++)
        {
            if(D[i].type==1&&!cnt) res+=D[i].ang-D[i-1].ang;//线段覆盖
            cnt+=D[i].type;
        }
        res+=pi2-D[tot].ang;
        return C[p].r*res;
    }
    int main()
    {
        n=read(); db a,b,c,ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&a,&b,&c);
            C[i]=Circ( Poi(b,c) , a );
        }
        for(int i=1;i<=n;i++) ans+=work(i);
        printf("%.3f
    ",ans);
        return 0;
    }
  • 相关阅读:
    软件工程实践总结
    2020软件工程第五次作业05
    软件工程问题清单
    2020软件工程第四次作业04
    用SQL*Plus命令启动和关闭数据库
    2020软件工程第三次作业03
    2020软件工程作业02
    图像处理问题清单
    2020软件工程作业01
    Markdown 快速入门
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11438632.html
Copyright © 2011-2022 走看看