Bzoj2178 圆的面积并

Time Limit: 20 Sec  Memory Limit: 259 MB
Submit: 1720  Solved: 441

Description

给出N个圆,求其面积并

Input

先给一个数字N ,N< = 1000 接下来是N行是圆的圆心,半径,其绝对值均为小于1000的整数

Output

面积并,保留三位小数

正解是计算几何,也可以用simpson积分强行搞。

这里解法是simpson积分

数据炒鸡不友好,精度必须要1e-13才行,于是轻松过SPOJ那道圆面积并的代码被轻松卡掉。

开始尝试各种细节剪枝,比如说删掉所有被大圆包含的小圆,比如说只算有圆的横坐标而跳过空区域,比如说solve的时候多传一个面积参数……

然而还是T得飞起,折腾了一下午,突然发现popoQQQ大神在算f(x)的时候加了个记忆化。http://blog.csdn.net/popoqqq/article/details/42292313

并不会用static,姑且仿照着写了记忆化,成功AC。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<map>
  7 using namespace std;
  8 const double eps=1e-13;
  9 const int INF=1e9;
 10 const int mxn=1010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10-'0'+ch;ch=getchar();}
 15     return x*f;
 16 }
 17 //
 18 struct cir{
 19     int x,y,r;
 20     friend bool operator < (const cir a,const cir b){return a.r<b.r;}
 21 }c[mxn];int cnt=0;
 22 inline double dist(cir a,cir b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
 23 //
 24 struct line{
 25     double l,r;
 26     friend bool operator <(const line a,const line b){return a.l<b.l;}
 27 }a[mxn],b[mxn];int lct=0;
 28 
 29 
 30 double f(double x){
 31     static map<double,double>mp;
 32     static map<double,double>::iterator it;
 33     if((it=mp.find(x))!=mp.end())return it->second;
 34     double &re=mp[x];
 35     int i,j;
 36     lct=0;
 37     for(i=1;i<=cnt;i++){//计算直线截得圆弧长度 
 38         double dd=c[i].x-x;
 39         if(fabs(dd)>=c[i].r)continue;
 40         double h= sqrt(c[i].r*c[i].r-dd*dd);
 41         a[++lct].l=c[i].y-h;
 42         a[lct].r=c[i].y+h;
 43     }
 44     if(!lct)return re=0.0;
 45     double last=-INF;
 46     sort(a+1,a+lct+1);
 47     for(i=1;i<=lct;i++){//线段长度并 
 48         if(a[i].l>last){re+=a[i].r-a[i].l;last=a[i].r;}
 49         else if(a[i].r>last){re+=a[i].r-last;last=a[i].r;}
 50     }
 51 //    printf("x:%.3f  len:%.3f
",x,len);
 52     return re;
 53 }
 54 inline double sim(double l,double r){
 55     return (f(l)+4*f((l+r)/2)+f(r))*(r-l)/6;
 56 }
 57 double solve(double l,double r,double S){
 58     double mid=(l+r)/2;
 59     double ls=sim(l,mid);
 60     double rs=sim(mid,r);
 61     if(fabs(rs+ls-S)<eps)return ls+rs;
 62     return solve(l,mid,ls)+solve(mid,r,rs);
 63 }
 64 int n;
 65 double ans=0;
 66 bool del[mxn];
 67 int main(){
 68     freopen("cir.in","r",stdin);
 69     n=read();
 70     int i,j;
 71 
 72     for(i=1;i<=n;i++){
 73         c[i].x=read();    c[i].y=read();    c[i].r=read();
 74 //        scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].r);
 75     }
 76     //
 77     sort(c+1,c+n+1);
 78     for(i=1;i<n;i++)
 79         for(j=i+1;j<=n;j++){
 80             if((double)c[j].r-c[i].r>=dist(c[i],c[j]))
 81                 {del[i]=1;break;}
 82         }
 83     for(i=1;i<=n;i++)
 84         if(!del[i])c[++cnt]=c[i];
 85     //删去被包含的圆
 86     double tmp=-INF;int blct=0;
 87     for(i=1;i<=cnt;i++){
 88         b[++blct].l=c[i].x-c[i].r;
 89         b[blct].r=c[i].x+c[i].r;
 90     }
 91     sort(b+1,b+blct+1);
 92     double L=-INF;
 93     for(i=1;i<=blct;i++){
 94         if(b[i].r<=tmp)continue;
 95         L=max(tmp,b[i].l);
 96         ans+=solve(L,b[i].r,sim(L,b[i].r));
 97         tmp=b[i].r;
 98     }
 99     printf("%.3f
",ans);
100     return 0;
101 }

  

原文地址:https://www.cnblogs.com/SilverNebula/p/6351792.html