日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

[SPOJ CIRU]The area of the union of circles(自适应Simpson积分求圆并面积)

發(fā)布時(shí)間:2023/12/14 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [SPOJ CIRU]The area of the union of circles(自适应Simpson积分求圆并面积) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16754

題目大意

求圓的面積并

思路

首先膜拜一發(fā)福大核武的神做法
http://hi.baidu.com/aekdycoin/item/b8ff6adc73c0e71dd78ed0d6
這種做法在applepi大爺?shù)挠?jì)算幾何講義中也有提到過,非常神奇優(yōu)美,但是很不好寫,畢竟不是所有人都像核武大爺那樣神犇,沒有很強(qiáng)的可推廣性。

再來(lái)膜拜一發(fā)七爺?shù)淖赃m應(yīng)Simpson積分題解
http://hi.baidu.com/sevenkplus/item/8cf47779e1e83b376cc37caa

自適應(yīng)Simpson積分來(lái)求圓并的做法,就是用f(x)來(lái)表示一根穿過了橫坐標(biāo)為x的掃描線,被圓形覆蓋的長(zhǎng)度,那么f(x)的圖像是在一段一段的區(qū)間中是連續(xù)的,并且函數(shù)的曲線肯定是在x軸的上方。而且顯然最終的圓并面積就是f(x)的圖像與x軸圈起來(lái)的面積,我們可以用數(shù)值積分來(lái)求這個(gè)圖像的面積,數(shù)值積分分三種:矩形、梯形、Simpson,其中Simpson積分的做法就是把函數(shù)圖像用一根二次函數(shù)曲線來(lái)擬合,精度最高。
而自適應(yīng)Simpson積分,簡(jiǎn)單地說(shuō)就是在當(dāng)前區(qū)間直接擬合的精度足夠的情況下,就不會(huì)繼續(xù)遞歸到左右兩半?yún)^(qū)間再做Simpson積分,提高了算法的效率。

看起來(lái)這個(gè)玩意就是亂搞嘛是不是= =,似乎看上去很不靠譜,但是實(shí)際上非常好用,除非一些特殊的反例(http://wapapp.baidu.com/shuxk/item/bd1210284b5d2e869c63d1b7),不光是圓的面積并,只要你會(huì)求出某種圖形蓋在掃描線上的區(qū)間,幾乎任何玩意的面積并都是可以求的,實(shí)為殺人越貨之利器23333。

那么我們就是要把所有圓分成一坨一坨圓,每一坨圓是連在一塊的,對(duì)于每一坨圓,它們的f(x)圖像肯定是連續(xù)的,就能用自適應(yīng)Simpson積分把這一坨圓的面積求出來(lái),累加答案即可。
當(dāng)然還要注意怎么求一根掃描線被圓覆蓋的長(zhǎng)度,這和之前我做的下落的圓盤那題差不多,也是個(gè)比較簡(jiǎn)單的區(qū)間貪心問題,而找一坨一坨圓也是一樣的貪心,只不過是在x軸上做貪心而已,怎么做相信大家都會(huì),渣渣我就不說(shuō)了。

嘴巴上講講做法當(dāng)然很簡(jiǎn)單,但是我還是花了一個(gè)白天的時(shí)間才A掉這題,因此還要注意一些細(xì)節(jié):
1、EPS開1e-6足矣,1e-7也可以,不過速度慢了4倍
2、此題很卡精度和細(xì)節(jié),判<EPS神馬的必須取等號(hào),比如說(shuō)寫成<<script id="MathJax-Element-1121" type="math/tex"><</script>EPS就會(huì)WA,寫成<=<script id="MathJax-Element-1122" type="math/tex"><=</script>EPS就沒問題,不過在1e-7精度下沒問題,坑爹啊
3、找區(qū)間并的長(zhǎng)度的貪心很簡(jiǎn)單,但是還是要注意,不能掉以輕心(看我注釋中的感嘆號(hào)就是我WA的地方)
4、要做一個(gè)預(yù)處理,刪掉所有被其他大圓完全覆蓋的小圓,否則會(huì)WA,不要問我為什么,我也不知道,親測(cè)WA,扒了別人代碼才發(fā)現(xiàn)問題的。

代碼

//自適應(yīng)Simpson積分 #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> #include <cmath>#define MAXN 10000 #define EPS 1e-6using namespace std;int n;struct Point //點(diǎn) {double x,y;Point(){}Point(double _x,double _y):x(_x),y(_y){}bool operator<(const Point &b)const { return x==b.x?y<b.y:x<b.x; } };struct Circle //圓 {Point o;double r;Circle(){}Circle(Point _o,double _r):o(_o),r(_r){} }circles[MAXN],tmp[MAXN];bool cmp2(Circle a,Circle b) {return a.r>b.r; }bool cmp(Circle a,Circle b) {if(fabs(a.o.x-a.r-b.o.x+b.r)<=EPS) return a.o.x+a.r<b.o.x+b.r;return a.o.x-a.r<b.o.x-b.r; }pair<double,double>intervals[MAXN]; int tot=0; int st,ed;bool check(Circle a,Circle b) //檢查b是否被套在a里面 {return (a.o.x-b.o.x)*(a.o.x-b.o.x)+(a.o.y-b.o.y)*(a.o.y-b.o.y)<=(a.r-b.r)*(a.r-b.r); }void prework() {sort(circles+1,circles+n+1,cmp2);int cnt=0;for(int i=1;i<=n;i++){bool flag=true;for(int j=1;j<=cnt;j++)if(check(tmp[j],circles[i])){flag=false;break;}if(flag) tmp[++cnt]=circles[i];}n=cnt;for(int i=1;i<=n;i++)circles[i]=tmp[i]; }void getCircleIntersec(Circle a,double x) //求x=x這條平行于y軸的直線穿過圓a的長(zhǎng)度 {intervals[++tot]=make_pair(a.o.y-sqrt(a.r*a.r-(x-a.o.x)*(x-a.o.x)),a.o.y+sqrt(a.r*a.r-(x-a.o.x)*(x-a.o.x))); }double f(double x) //求掃描線x被圓覆蓋部分的長(zhǎng)度 {tot=0;for(int i=st;i<=ed;i++)if(x<circles[i].o.x+circles[i].r&&x>circles[i].o.x-circles[i].r)getCircleIntersec(circles[i],x);sort(intervals+1,intervals+tot+1);double ans=0,start=-1e12,end=-1e12; //!!!!!!!!!!!for(int i=1;i<=tot;i++){if(intervals[i].first>=end){ans+=end-start;start=intervals[i].first;end=intervals[i].second;}else end=max(end,intervals[i].second);}ans+=end-start;return ans; }double calc(double len,double fL,double fM,double fR) //求長(zhǎng)度為len的[L,R]區(qū)間,中點(diǎn)為M的Simpson近似面積 {return (fL+4*fM+fR)*len/6; }double Simpson(double L,double M,double R,double fL,double fM,double fR,double sqr) //Simpson積分求區(qū)間[L,R]的面積并,f(L)=L,f(R)=R,f(M)=M,把[L,R]當(dāng)成整體來(lái)擬合得到的面積是sqr {double M1=(L+M)/2,M2=(M+R)/2;double fM1=f(M1),fM2=f(M2);double g1=calc(M-L,fL,fM1,fM),g2=calc(R-M,fM,fM2,fR);if(fabs(sqr-g1-g2)<=EPS) //把當(dāng)前區(qū)間分成2半再擬合得到的答案差別很小,就不再遞歸下去了return g1+g2;return Simpson(L,M1,M,fL,fM1,fM,g1)+Simpson(M,M2,R,fM,fM2,fR,g2); }int main() {double ans=0;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&circles[i].o.x,&circles[i].o.y,&circles[i].r);prework();sort(circles+1,circles+n+1,cmp);for(int i=1,j;i<=n;i++){double L=circles[i].o.x-circles[i].r,R=circles[i].o.x+circles[i].r;for(j=i+1;j<=n;j++){if(circles[j].o.x-circles[j].r>R) break;else R=max(R,circles[j].o.x+circles[j].r); //!!!!!!!!!!!!!!}double M=(L+R)/2;st=i,ed=j-1;i=j-1;double fL=f(L),fM=f(M),fR=f(R);ans+=Simpson(L,M,R,fL,fM,fR,calc(R-L,fL,fM,fR));}printf("%.3lf\n",ans);return 0; }

總結(jié)

以上是生活随笔為你收集整理的[SPOJ CIRU]The area of the union of circles(自适应Simpson积分求圆并面积)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。