zoukankan      html  css  js  c++  java
  • bzoj 2178 圆的面积并 —— 辛普森积分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2178

    先看到这篇博客:https://www.cnblogs.com/heisenberg-/p/6740654.html

    好像本应算弓形面积、三角形面积之类的,但不会...于是用辛普森积分硬做...

    参考了这篇博客:https://blog.csdn.net/orpinex/article/details/7311363

    然而如果写成精度友好型的 asr ( *15, /15, eps/2 ),或T或RE的,不精度友好反而好了...

    为什么一开始传的范围是所有圆边界的 min, max 就会WA,传 -inf, inf 就A了...

    总之写的时候还是尽量稳妥一点吧...

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef double db;
    int const xn=1005,inf=2005;
    db const eps=1e-8;
    int n;
    bool tmp[xn];
    struct N{int x,y,r;}c[xn];
    struct S{db l,r;}seg[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int dmp(db x)
    {
      if(fabs(x)<eps)return 0;
      else if(x>eps)return 1;
      else return -1;
    }
    db sqr(db x){return x*x;}
    bool cmp(S a,S b){return dmp(a.l-b.l)<0||(dmp(a.l-b.l)==0&&dmp(a.r-b.r)<0);}
    bool cmp2(N a,N b){return a.r<b.r;}
    db maxx(db x,db y){if(dmp(x-y)<0)return y; return x;}
    bool in(int a,int b){return sqr(c[a].x-c[b].x)+sqr(c[a].y-c[b].y)<=sqr(c[a].r-c[b].r);}
    void init()
    {
      sort(c+1,c+n+1,cmp2);
      for(int i=1;i<=n;i++)
        {
          for(int j=i+1;j<=n;j++)
        if(in(i,j)){tmp[i]=1; break;}
        }
      int tot=0;
      for(int i=1;i<=n;i++)if(!tmp[i])c[++tot]=c[i];
      n=tot;
    }
    db f(db x)
    {
      int cnt=0;
      for(int i=1;i<=n;i++)
        {
          if(dmp(fabs(c[i].x-x)-c[i].r)>0)continue;
          db dis=sqrt(sqr(c[i].r)-sqr(x-c[i].x));
          seg[++cnt].l=c[i].y-dis; seg[cnt].r=c[i].y+dis;
        }
      sort(seg+1,seg+cnt+1,cmp);
      db ret=0,r=-inf;
      for(int i=1;i<=cnt;i++)
        {
          if(dmp(seg[i].l-r)>0)ret+=seg[i].r-seg[i].l,r=seg[i].r;
          else if(dmp(seg[i].r-r)>0)ret+=seg[i].r-r,r=seg[i].r;
        }
      return ret;
    }
    db simp(db l,db r){return (r-l)/6*(f(l)+4*f((l+r)/2)+f(r));}
    db asr(db l,db r,db eps,db lst)
    {
      db mid=(l+r)/2;
      db ls=simp(l,mid),rs=simp(mid,r);
      if(fabs(ls+rs-lst)<=15*eps)return ls+rs+(ls+rs-lst)/15;
      return asr(l,mid,eps/2,ls)+asr(mid,r,eps/2,rs);
    }
    db asr(db l,db r,db lst)
    {
      db mid=(l+r)/2;
      db ls=simp(l,mid),rs=simp(mid,r);
      if(fabs(ls+rs-lst)<=eps)return ls+rs;
      return asr(l,mid,ls)+asr(mid,r,rs);
    }
    int main()
    {
      n=rd(); int L=inf,R=-inf;
      for(int i=1;i<=n;i++)
        c[i].x=rd(),c[i].y=rd(),c[i].r=rd(),
          L=min(L,c[i].x-c[i].r),R=max(R,c[i].x+c[i].r);
      init();
      //printf("%.3f
    ",asr(L,R,eps,simp(L,R)));
      //printf("%.3f
    ",asr(L,R,simp(L,R)));
      printf("%.3f
    ",asr(-inf,inf,simp(-inf,inf)));
      //printf("%.3f
    ",asr(-inf,inf,eps,simp(-inf,inf)));
      return 0;
    }
    View Code

    然而这样其实会错HAHA,随便来个数据竟然就错了:

    3
    0 0 1
    0 0 1
    100 100 1

    应该输出 6.283,但上面的代码以及许多题解输出都是 3.142 ...

    于是换了一种写法,对每个连续段做积分,这样避免了空白区域对积分结果的影响;

    而且发现求一次 f(x) 很慢,所以之前求过的尽量重复利用;

    然后就T了,调了两小时...

    TLE 的原因竟然是 sort 里面传了 cmp() 函数??!!!如果改成重载结构体小于号,就不T了呵呵-_-

    所以还是要注意代码习惯阿。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef double db;
    int const xn=1005,inf=2005;
    db const eps=1e-13;
    int n,st,ed,xl[xn],xr[xn];
    bool tmp[xn];
    struct N{
      int x,y,r;
      bool operator < (const N &b) const
      {return r<b.r;}
    }c[xn];
    struct S{
      db l,r;
      bool operator < (const S &b) const
      {return l<b.l;}
    }seg[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    db sqr(db x){return x*x;}
    //bool cmp(S a,S b){return a.l<b.l;}
    //bool cmp2(N a,N b){return a.r<b.r;}
    bool cmp3(N a,N b){return a.x-a.r<b.x-b.r;}
    bool in(int a,int b){return sqr(c[a].x-c[b].x)+sqr(c[a].y-c[b].y)<=sqr(c[a].r-c[b].r);}
    void init()
    {
      sort(c+1,c+n+1);//cmp2
      for(int i=1;i<=n;i++)
        {
          for(int j=i+1;j<=n;j++)
        if(in(i,j)){tmp[i]=1; break;}
        }
      int tot=0;
      for(int i=1;i<=n;i++)if(!tmp[i])c[++tot]=c[i];
      n=tot;
      sort(c+1,c+n+1,cmp3);//
    }
    db f(db x)
    {
      int cnt=0;
      for(int i=st;i<=ed;i++)
        {
          if(xl[i]>=x||xr[i]<=x)continue;
          db dis=sqrt(c[i].r-sqr(x-c[i].x));//(sqr)
          seg[++cnt].l=c[i].y-dis; seg[cnt].r=c[i].y+dis;
        }
      sort(seg+1,seg+cnt+1);//cmp
      db ret=0,r=-inf;
      for(int i=1,j;i<=cnt;i=j)
        {
          r=seg[i].r;
          for(j=i+1;j<=cnt&&seg[j].l<=r;j++)
        if(r<seg[j].r)r=seg[j].r;
          ret+=r-seg[i].l; 
        }
      return ret;
    }
    db simp(db len,db fl,db fr,db fm){return len/6*(fl+4*fm+fr);}
    db asr(db l,db r,db mid,db fl,db fr,db fm,db lst)
    {
      db lmid=(l+mid)/2,flm=f(lmid),rmid=(mid+r)/2,frm=f(rmid);
      db ls=simp(mid-l,fl,fm,flm),rs=simp(r-mid,fm,fr,frm);
      if(fabs(ls+rs-lst)<=eps)return ls+rs;
      return asr(l,mid,lmid,fl,fm,flm,ls)+asr(mid,r,rmid,fm,fr,frm,rs);
    }
    int main()
    {
      n=rd();
      for(int i=1;i<=n;i++)
        c[i].x=rd(),c[i].y=rd(),c[i].r=rd();
      init(); db ans=0;
      for(int i=1;i<=n;i++)
        xl[i]=c[i].x-c[i].r,xr[i]=c[i].x+c[i].r,c[i].r=c[i].r*c[i].r;
      for(int i=1,j;i<=n;i=j)
        {
          int l=xl[i],r=xr[i];
          for(j=i+1;xl[j]<=r&&j<=n;j++)if(xr[j]>r)r=xr[j];
          st=i; ed=j-1; db mid=(l+r)/2;
          db fl=f(l),fm=f(mid),fr=f(r);
          ans+=asr(l,r,mid,fl,fr,fm,simp(r-l,fl,fr,fm));
        }
      printf("%.3f
    ",ans);
      return 0;
    }
    View Code
  • 相关阅读:
    基于应用外壳的架构
    示例代码和环境配置
    获取元素位置信息:getBoundingClientRect
    nodejs学习记录
    网页整理 --- 要换工作了,把这一堆网页先存起来
    删除网页上的广告
    周数的处理
    十六进制
    [例]字体改变,文章位置不变
    haslayout和BFC
  • 原文地址:https://www.cnblogs.com/Zinn/p/10142646.html
Copyright © 2011-2022 走看看