bzoj 1043: [HAOI2008]下落的圆盘

Description

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

Input

n ri xi y1 ... rn xn yn

Output

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

Sample Input

2
1 0 0
1 1 0

Sample Output

10.472

HINT

数据规模

n<=1000


因为n只有1000.所以对于每个圆。处理其后面落下来的环覆盖的部分,然后求和即可。

反三角函数 atan2(y,x)

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
double pi=3.141592653;
struct circle
{
     double r;
     double x,y;
}a[1001];
struct cover
{
     double se,ee;
}b[10001];
inline bool cmp(cover x,cover y)
{
     if(x.se<y.se)
          return true;
     if(x.se==y.se&&x.ee<y.ee)
          return true;
     return false;
}
int main()
{
     int n;
     scanf("%d",&n);
     int i,j,k;
     for(i=1;i<=n;i++)
          scanf("%lf%lf%lf",&a[i].r,&a[i].x,&a[i].y);
     double ans=0;
     for(i=1;i<=n;i++)
     {
     	  int p=0;
          for(j=i+1;j<=n;j++)
          {
               double dis=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);
               if(dis==0)
               {
               	    if(a[i].r<a[j].r)
                    {
					     p++;
                         b[p].se=0;
                         b[p].ee=double(2)*pi;
                         break;
                    }
                    else
                         continue;
               }
               if(dis>(a[i].r+a[j].r)*(a[i].r+a[j].r))
                    continue;
               if(dis<(a[i].r-a[j].r)*(a[i].r-a[j].r))
               {
               	    if(a[i].r<a[j].r)
                    {
					     p++;
                         b[p].se=0;
                         b[p].ee=double(2)*pi;
                         break;
                    }
                    else
                         continue;
               }
               double dx=a[j].x-a[i].x,dy=a[j].y-a[i].y;
               double de=atan2(dy,dx);
               if(de<0)
                    de=double(2)*pi+de;
               double dre=acos((a[i].r*a[i].r+dis-a[j].r*a[j].r)/(double(2)*a[i].r*sqrt(dis)));
               p++;
               b[p].se=de-dre;
               b[p].ee=de+dre;
               if(b[p].se<0&&b[p].ee<0)
               {
                    b[p].se=double(2)*pi+b[p].se;
                    b[p].ee=double(2)*pi+b[p].ee;
               }
               else if(b[p].se<0)
               {
                    double tse=b[p].se,tee=b[p].ee;
                    b[p].se=double(2)*pi+b[p].se;
                    b[p].ee=double(2)*pi;
                    p++;
                    b[p].se=0;
                    b[p].ee=tee;
               }
               else if(b[p].se>double(2)*pi&&b[p].ee>double(2)*pi)
               {
                    b[p].se-=double(2)*pi;
                    b[p].ee-=double(2)*pi;
               }
               else if(b[p].ee>double(2)*pi)
               {
                    double tse=b[p].se,tee=b[p].ee;
                    b[p].se=tse;
                    b[p].ee=double(2)*pi;
                    p++;
                    b[p].se=0;
                    b[p].ee=tee-double(2)*pi;
               }
          }
          sort(b+1,b+1+p,cmp);
          double len=0;
          for(j=1;j<=p;j++)
          {
          	   double l=b[j].se,r=b[j].ee;
               for(k=j+1;k<=p;k++)
               {
                    if(b[k].se>r)
                         break;
                    if(b[k].ee>r)
                         r=b[k].ee;
               }
               len+=(r-l);
               j=k-1;
          }
          ans+=(double(2)*pi-len)*a[i].r;
          //printf("%lf\n",len);
     }
     printf("%.3lf\n",ans);
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值