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\n",asr(L,R,eps,simp(L,R)));//printf("%.3f\n",asr(L,R,simp(L,R)));printf("%.3f\n",asr(-inf,inf,simp(-inf,inf)));//printf("%.3f\n",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);//cmp2for(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);//cmpdb 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\n",ans);return 0; }
View Code
转载于:https://www.cnblogs.com/Zinn/p/10142646.html
bzoj 2178 圆的面积并 —— 辛普森积分相关推荐
- bzoj2178 圆的面积并
2178: 圆的面积并 Time Limit: 20 Sec Memory Limit: 259 MB Submit: 1318 Solved: 341 [ Submit][ Status][ ...
- 对圆柱面的曲面积分_计算对面积的曲面积分zds 圆柱面x^2+y^2=1介于平面z=0 和z=3之间的部分...
加个du盖子S1:x²+y²≤4的上侧.S1和S构成封闭zhi曲面的外侧.对daoS1+S应用GAUSS,有 ∫专∫ (z^2+x)dydz-zdxdy = ∫∫∫ 0 dv=0.S1+S Ω盖子属S ...
- [BZOJ1502]月下柠檬树(自适应辛普森积分)
1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1387 Solved: 739 [Submit][Statu ...
- [NOI2005] 月下柠檬树 (自适应辛普森积分)
题目 原题链接:点这里 总体思路–>问题转化 先将原本的柠檬树分解成为多个圆台,再单独看圆台的投影 一个圆在地面的投影,是等比例的,而一条竖线的投影长度d=htanαd=\cfrac{h}{\ ...
- [BZOJ1502][NOI2005]月下柠檬树(辛普森积分+解析几何)
题目: 我是超链接 题解: 首先我们理解一下投影的性质,也就是投影出来的图形一定跟原图形全等. 考虑一下圆形投影下来是什么呢?和原来一样的圆形啊 怎么转化竖着的树呢? 也就是树高*cot(α) 那么我 ...
- [BZOJ1502][NOI2005]月下柠檬树(辛普森积分)
=== === 这里放传送门 === === 题解 据说这题正解好像是各种分类讨论一块块求面积? 然而一开始知道这题辛普森积分就可以过但是差一点还是写成了那种分类讨论的方法..就一开始非常无脑求了公切 ...
- java使用蒙特卡罗方法计算半径为r圆的面积_不用微积分,如何计算圆面积
选自medium 作者:Andre Ye 机器之心编译 机器之心编辑部 杀鸡用牛刀,我们用机器学习方法来算圆的面积. 询问任何人圆的面积是多少,他们都会告诉你不就是r²吗.但如果你问他们为什么,他们很 ...
- 土气和洋气的方法不用π求圆的面积
昨天写了一篇短文: 说说的那道求面积的小学六年级几何题:https://blog.csdn.net/dog250/article/details/84778239 这篇文章主要是就着一道简单的求面积的 ...
- 微积分(一)一般概念以及从圆的面积怎么来?
今天开始回忆或者说重学一下微积分,在此记录一下课程总结以及拓展. 我们都知道圆的面积是,但是,为什么呢?我们来看一下这个公式的由来.仔细观察我们就能发现了解的微积分中的几个idea:积分,导数. 假设 ...
最新文章
- ASP.NET页面传值的几种方式
- innodb参数汇总
- Python学习笔记010——作用域
- apache安全设置
- Command ‘ifconfig‘ not found
- PHP 长文章分页函数
- C# 使用XML序列化对象(一)
- 第六章 计算机网络与i教案,大学计算机基础教案第6章计算机网络基础与应用.docx...
- redis——新版复制
- [Algorithm]一切始于ADT-表达式计算
- python自带的用于解析HTML的库HtmlParser
- 《树莓派实战秘籍》——1.20 技巧20使用Swap添加额外的内存
- GENTLE.NET快速上手
- 谷粒商城doc文档_谷粒学院项目分享全栈开发入门必备(资料齐全)
- jvisualvm使用
- 怎么删除映射网络里的计算机,W7怎么样删除映射上网网络驱动器
- AspNetPager 存储过程
- 王二的经济学故事读书笔记
- 福特汉姆计算机专业,福特汉姆大学计算机如何
- 2008Noip解题报告