[HAOI2008]下落的圆盘

直接暴力O(n^2)枚举 每一个圆盘和其后面落下的圆盘

i 当前枚举的圆 j i之后的圆

然后利用atan2函数求出(x[j]-x[i],y[j]-y[i])向量与x轴的夹角

再根据d(圆心之间距离)、r[i]、r[j]余弦定理求出向量可以向上下扩展的角度

用贪心线段覆盖...

枚举的时候有几种特殊情况:

1.两个圆相离

2.i在j内

3.j在i内

4.斜率不存在的情况不用考虑,atan2函数就行了

 

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define dd double
using namespace std;
const int N=1006;
const dd pai=acos(-1.0);

struct son
{
    dd l,r;
    bool friend operator < (son a,son b)
    {
        if(a.l==b.l)
            return a.r<b.r;
        return a.l<b.l;
    }
}ji[N*10];
int con;

int n;
dd r[N],x[N],y[N];

inline dd dis(dd x3,dd y3,dd x4,dd y4)
{
    return sqrt( (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3) );
}

dd check()
{
    sort(ji+1,ji+1+con);

    dd ans=0,las=-pai;
    for(int i=1;i<=con;++i)
    {
        if(ji[i].l<las)
        {
            if(ji[i].r>las)
                ans+=(ji[i].r-las);
        }
        else
        {
            ans+=(ji[i].r-ji[i].l);
        }
        if(las<ji[i].r)
            las=ji[i].r;
    }
    return ans;
}

dd work()
{
    dd ce1,ce2,d,ans=0,temp,sh,xi;
    for(int i=1;i<=n;++i)
    {
        con=0;
        for(int j=i+1;j<=n;++j)
        {
            d=dis(x[i],y[i],x[j],y[j]);
            if(d>r[i]+r[j])//i和j相离
                continue;
            if(d+r[i]<r[j])//i整个被覆盖
            {
                ji[++con]=(son){-pai,pai};
                break;
            }
            if(d+r[j]<r[i])//j在i中间
                continue;
            /*if(x[j]==x[i])
                ce1=(y[j]-y[i]>0?pai/2.0:-pai/2.0);//直角 .... (还是别判断了...容易wa)
            else*/
            ce1=atan2( (x[j]-x[i]),(y[j]-y[i]) );
            ce2=acos( (r[i]*r[i]+d*d-r[j]*r[j])/(2*r[i]*d) );

            sh=ce1+ce2;xi=ce1-ce2;
            if(sh>pai)
                ji[++con]=(son){ -pai,sh-2*pai },sh=pai;
            if(xi<-pai)
                ji[++con]=(son){ xi+2*pai,pai },xi=-pai;
            ji[++con]=(son){ xi,sh };

        }
        temp=check();
        //printf("temp=%lf\n",temp);
        ans+=((2.0*pai-temp)*r[i]);
    }
    return ans;
}

int main(){

    //freopen("in.in","r",stdin);
    //freopen("disc.in","r",stdin);
    //freopen("disc.out","w",stdout);

    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%lf%lf%lf",&r[i],&x[i],&y[i]);
    printf("%.3lf",work());
}
下落的圆盘

 

posted @ 2017-10-02 16:21  A_LEAF  阅读(322)  评论(0编辑  收藏  举报