【题解】CIRU - The area of the union of circles [SP8073] \ 圆的面积并 [Bzoj2178]

传送门:

【题目描述】

给出 \(n\) 个圆的圆心坐标 \((x,y)\) 和半径 \(r\),求它们覆盖的总面积。

【输入】

第一行一个整数 \(n\),表示一共有 \(n\) 个圆,接下来 \(n\) 行每行三个整数 \(x,y,r\) 。

【输出】

答案保留三位小数。

【样例】

  1. 样例输入:
  2. 3
  3. 0 0 1
  4. 0 0 1
  5. 100 100 1
  6. 样例输出:
  7. 6.283

【数据范围】

\(100 \%:\) \(1 \leqslant n \leqslant 1000,\) \(|x|,|y| \leqslant 1000,\) \(0 \leqslant r \leqslant 1000\)

【分析】

【计算几何全家桶】

圆面积并的板题。

【前置芝士】

自适应辛普森积分 (乱搞)。

虽然不知道积分是什么东西,但老师说只要背了公式而且会用它求面积就可以了:\(ans(l,r)=\frac{(r-l)(F_l+4F_{mid}+F_r)}{6}\) 。

当计算平面图形面积时,\(F_Y\) 就是直线 \(y=Y\) 穿过图形的部分的长度。

例:一个底为 \(a\),高为 \(h\) 的三角形面积可表示为: \(S=\frac{h*(a+4*\frac{a}{2}+0)}{6}=\frac{a*h}{2}\) 。如下图,\(r-l=h,F_l=a,F_{mid}=\frac{a}{2},F_r=0\):

(另外,当计算立体图形体积时,\(F_Y\) 就是平面 \(z=Y\) 穿过图形的部分的面积。例:一个半径为 \(r\) 的球体积可表示为: \(V=\frac{2r*(0+4\pi r^2+0)}{6}=\frac{4\pi r^3}{3}\) )

但并不是所有的图形都可以这样子做,比如在求圆面积时就会出问题(设半径为 \(r\)): \(S=\frac{2r*(0+4*2r+0)}{6}=\frac{4 r^2}{3} \neq \pi r^2\) 。

这时候就需要用到自适应辛普森法:分别用公式出 \(ans(l,mid)\) 和 \(ans(mid,r)\),若二者之和与 \(ans(l,r)\) 的差值小于 \(eps\),则返回 \(ans(l,r)\),否则递归求解 \((l,mid)\) 与 \((mid,r)\) 再加起来。

代码如下:

  1. #define LD double
  2. #define Rd register LD
  3. inline LD F(Rd Y){return ???;}//视情况而定
  4. inline LD Simpson(Rd L,Rd R){return (R-L)*(F(L)+4.0*F((L+R)*0.5)+F(R))/6.0;}//套公式
  5. inline LD sakura(Rd L,Rd R,Rd now){//求解ans(L,R)
  6. Rd mid=(L+R)*0.5,FL=Simpson(L,mid),FR=Simpson(mid,R);//先用公式求左右两边
  7. if(!dcmp(now-FL-FR))return now;//满足精度要求
  8. return sakura(L,mid,FL)+sakura(mid,R,FR);//递归求解并求和
  9. }

【问题求解】

回到这道题,求出最靠边上的两端点 \(Y_{min},Y_{max}\) 直接递归求解即可,至于上面的 \(F\) 函数可以暴力枚举所有圆求交弦,然后对其排序做线段覆盖。

注意精度要调好,\(\text{Bzoj}\) 需要 \(1e\!-\!13\),\(\text{SPOJ}\) 需要 \(1e\!-\!7\) 。

时间复杂度: \(O( nlogn \times\) 玄学 \()\) 。其中 “玄学” 为 \(F\) 函数调用次数。

【优化】

只是单纯地求解 \((Y_{min},Y_{max})\) 会被 \(\text{Bzoj}\) 的 【变态毒瘤数据】 卡掉,\(\text{SPOJ}\) 也过不了。

为什么?

如果有 \(1\) 个孤零零的圆在最上面,\(999\) 个圆堆在最下面,最后算出来误差会非常大,所以要分段处理,即将所有圆划分为若干个联通块分别求解(可以将每个圆的上下端点连起来跑线段覆盖),这样子误差会小一些。

此时【变态毒瘤数据】成功地算了出来,但花了 \(30s\),考虑对 \(F\) 函数进行记忆化,再经过一波卡常,本机 \(10.6s\),交上去刚好卡过。

【再优化】

那么,连 【八聚氧】 都救不了的 \(\text{SPOJ}\) 又该怎么办呢?

提前预处理出大圆包含小圆的情况(把被包含的小圆删掉),大大减小 \(nlogn\) 部分的消耗。

呼呼,终于过了

【Code】

  1. #include<algorithm>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<map>
  5. #define LD double
  6. #define LL long long
  7. #define Re register int
  8. #define Rd register LD
  9. #define Vector Point
  10. using namespace std;
  11. const int N=2003;
  12. const LD eps=1e-13;
  13. int n,m;map<LD,LD>vis;
  14. inline int dcmp(Rd a){return a<-eps?-1:(a>eps?1:0);}
  15. struct Point{
  16. LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
  17. inline void in(){scanf("%lf%lf",&x,&y);}
  18. };
  19. struct Segment{
  20. LD L,R;Segment(LD l=0,LD r=0){L=l,R=r;}
  21. inline bool operator<(Segment O)const{return L!=O.L?L<O.L:R<O.R;}
  22. }Seg[N];
  23. struct Circle{
  24. LD x,y,r,L,R,D,U;
  25. inline void in(){scanf("%lf%lf%lf",&x,&y,&r),L=x-r,R=x+r,D=y-r,U=y+r;}
  26. inline bool operator<(Circle B)const{return D<B.D;}//按下端点排序
  27. }C[N],C_[N];
  28. inline bool cmp(Circle A,Circle B){return A.r<B.r;}//按半径排序
  29. inline LD dis(Circle A,Circle B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
  30. inline LD SS(Rd x){return x*x;}
  31. inline LD F(Rd Y){
  32. if(vis[Y])return vis[Y];//记忆化
  33. Re t=0;Rd ans=0;
  34. for(Re i=1;i<=n;++i)
  35. if(dcmp(Y-C[i].D)>0&&dcmp(Y-C[i].U)<0){//如果直线穿过了该圆
  36. Rd tmp=sqrt(SS(C[i].r)-SS(C[i].y-Y));//勾股定理求交弦
  37. if(dcmp(tmp)>0)Seg[++t]=Segment(C[i].x-tmp,C[i].x+tmp);
  38. }
  39. if(!t)return 0.0;
  40. sort(Seg+1,Seg+t+1);
  41. for(Re i=1,j;i<=t;i=j+1){
  42. Rd L=Seg[i].L,R=Seg[i].R;j=i;
  43. while(j<t&&Seg[j+1].L<=R)++j,R=max(R,Seg[j].R);
  44. ans+=R-L;
  45. }
  46. return vis[Y]=ans;
  47. }
  48. inline LD Simpson(Rd L,Rd R){return (R-L)*(F(L)+4.0*F((L+R)*0.5)+F(R))/6.0;}//【辛普森公式】
  49. inline LD sakura(Rd L,Rd R,Rd now){//【自适应】
  50. Rd mid=(L+R)*0.5,FL=Simpson(L,mid),FR=Simpson(mid,R);
  51. if(!dcmp(now-FL-FR))return now;
  52. return sakura(L,mid,FL)+sakura(mid,R,FR);
  53. }
  54. LD ans;
  55. int main(){
  56. // freopen("789.txt","r",stdin);
  57. scanf("%d",&m);
  58. for(Re i=1;i<=m;++i)C_[i].in();
  59. sort(C_+1,C_+m+1,cmp),C[++n]=C_[m];//按半径大小排序
  60. for(Re i=m-1;i>=1;--i){//【大圆吃小圆】从大圆向小圆枚举
  61. Re flag=1;
  62. for(Re j=1;j<=n&&flag;++j)
  63. if(dcmp(C_[i].r-C[j].r+dis(C_[i],C[j]))<=0)flag=0;//小r+大r <= dis,则说明小圆C_[i]被包含了在了C[j]以内
  64. if(flag)C[++n]=C_[i];//C_[i]没有被大圆包含
  65. }
  66. sort(C+1,C+n+1);
  67. for(Re i=1,j;i<=n;i=j+1){//【分段处理】每个联通块单独处理
  68. Rd D=C[i].D,U=C[i].U;j=i;
  69. while(j<n&&C[j+1].D<=U)++j,U=max(U,C[j].U);
  70. ans+=sakura(D,U,Simpson(D,U));
  71. }
  72. printf("%.3lf",ans);
  73. }

【题解】CIRU - The area of the union of circles [SP8073] \ 圆的面积并 [Bzoj2178]的更多相关文章

  1. SPOJ CIRU - The area of the union of circles (圆的面积并)

    CIRU - The area of the union of circles no tags  You are given N circles and expected to calculate t ...

  2. SPOJ CIRU The area of the union of circles

    You are given N circles and expected to calculate the area of the union of the circles ! Input The f ...

  3. SPOJ CIRU The area of the union of circles (计算几何)

    题意:求 m 个圆的并的面积. 析:就是一个板子题,还有要注意圆的半径为0的情况. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024 ...

  4. SPOJ CIRU The area of the union of circles ——Simpson积分

    [题目分析] 圆的面积并. 直接Simpson积分,(但是有计算几何的解法,留着flag). simpson积分,如果圆出现了不连续的情况,是很容易出事情的.(脑补一下) 但是没有什么办法,本来就是一 ...

  5. SPOJ 8073 The area of the union of circles (圆并入门)

    Sphere Online Judge (SPOJ) - Problem CIRU [求圆并的若干种算法,圆并扩展算法]_AekdyCoin的空间_百度空间 参考AekdyCoin的圆并算法解释,根据 ...

  6. [SPOJ-CIRU]The area of the union of circles/[BZOJ2178]圆的面积并

    [SPOJ-CIRU]The area of the union of circles/[BZOJ2178]圆的面积并 题目大意: 求\(n(n\le1000)\)个圆的面积并. 思路: 对于一个\( ...

  7. SPOJ 8073 The area of the union of circles(计算几何の圆并)(CIRU)

    Description You are given N circles and expected to calculate the area of the union of the circles ! ...

  8. SPOJ CIRU SPOJ VCIRCLE 圆的面积并问题

    SPOJ VCIRCLE SPOJ CIRU 两道题都是给出若干圆 就面积并,数据规模和精度要求不同. 求圆面积并有两种常见的方法,一种是Simpson积分,另一种是几何法. 在这里给出几何方法. P ...

  9. Maximal Area Quadrilateral CodeForces - 340B || 三点坐标求三角形面积

    Maximal Area Quadrilateral CodeForces - 340B 三点坐标求三角形面积(可以带正负,表示向量/点的不同相对位置): http://www.cnblogs.com ...

随机推荐

  1. Golang中的OO(面向对象)

    组合 > 继承 Go中的设计,以为继承的被诟病,所以Golang的设计团队在语言的设计时并没有采用经典的OO模式 那Golang中各个部分是怎么联系到一起的呢 type ReadWriter i ...

  2. MSSQL渗透测试

    mssql-getshell 来源:独自等待,知乎,github xp_cmdshell 第一种:在SQL Server 2005之前版本中,xp_cmdshell是默认开启的,因此可以直接利用,执行 ...

  3. 前端web安全-CSRF基础入门

    前言 今天找了个新地方进行学习 嘿嘿  采光不错!特别适合看书呢. 前言 1.CSRF 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click att ...

  4. 计算机&编程语言发展史

    计算机&编程语言发展史 编辑于2020-11-18 计算机的基本组成 计算机的发展经历了哪几代? 第一代 电子管计算机 第二代 晶体管计算机 第三代 集成电路计算机 第四代 大规模和超大规模集 ...

  5. 【MathType教学】表示分类的大括号怎么打

    大括号是一种常见的数学符号,可以用于集合.分段函数中,其实大括号还可以用来总结数学知识,比如对三角形进行分类,此时用的大括号可以称为表示分类的大括号.MathType作为专业的数学公式编辑器,可以快速 ...

  6. Word2 word输入公式+文字转表格

    1.word中输入 =rand() -点击回车键-会随机生成一段文字-可用作排版练习/虚拟的文字排版设计 ##也可以为=rand(2,3)等,括号里可以随即填写其他数字,最后生成文字字数等不一样 2. ...

  7. 对数组进行排序成最小的,相当于自己实现了一次String的compareTo函数,不过是另类的。

    题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. //一气呵成 ...

  8. Python GUI之Tkiner实战

    前言 Tkinter 是 Python 的标准 GUI 库.Python 使用 Tkinter 可以快速的创建 GUI 应用程序. 由于 Tkinter 是内置到 python 的安装包中.只要安装好 ...

  9. 【初等数论】裴蜀定理&扩展欧几里得算法

    裴蜀定理: 对于\(a,b\in N^*, x, y\in Z\),方程\(ax+by=k\)当且仅当\(gcd(a, b)|k\)时有解. 证明: 必要性显然. 充分性:只需证明当\(k=gcd(a ...

  10. 【CF620E】New Year Tree

    (题面来自luogu) 题意翻译 你有一棵以1为根的有根树,有n个点,每个节点初始有一个颜色c[i]. 有两种操作: 1 v c 将以v为根的子树中所有点颜色更改为c 2 v 查询以v为根的子树中的节 ...