BZOJ2178: 圓的面積並(格林公式)


題面

傳送門

題解

好神仙……

先給幾個定義

平面單連通區域:設\(D\)是平面內一區域,若屬於\(D\)內任一簡單閉曲線的內部都屬於\(D\),則稱\(D\)為單連通區域。通俗地說,單連通區域是沒有“洞”的區域。

正方向:當\(xOy\)平面上的曲線起點與終點重合時,則稱曲線為閉曲線。設平面的閉曲線L圍成平面區域\(D\),並規定當一個人沿閉曲線\(L\)環行時,區域\(D\)總是位於此人的左側,稱此人行走方向為曲線L關於區域\(D\)的正方向,反之為負方向。

格林公式:設\(D\)是一個平面單連通區域,\(L\)是它取正向的輪廓線(分段光滑),\(P,Q\)\(D\)上具有一階連續偏導數,則有格林公式

\[\int\int\limits_D\left({\partial Q\over \partial x}-{\partial P\over \partial y}\right)\mathrm dx\mathrm dy=\oint\limits_LP\mathrm dx+Q\mathrm dy \]

關於那個\(\oint\)就是一個有方向的\(\int\),直接當成\(\int\)看就好了

回到本題,我們令\(Q=x,P=-y\),我們要求的東西就是

\[\int\int\limits_D1\mathrm dx\mathrm dy={1\over 2}\oint\limits_L-y\mathrm dx+x\mathrm dy \]

這樣轉化之后,我們就可以把圓的面積轉化成跟輪廓線有關的計算了

因為圓弧上\(x,y\)很麻煩,我們用角度來表示它

\[\begin{aligned} \int\limits_L-y\mathrm dx+x\mathrm dy &=\int\limits_L-(y_0+r\sin t)\mathrm d(x_0+r\cos t)+(x_0+r\cos t)\mathrm d(y_0+r\sin t)\\ &=\int\limits_L(y_0+r\sin t)(r\sin t)+(x_0+r\cos t)(r\cos t)\\ &=r\int\limits_L(y_0+r\sin t)\sin t+(x_0+r\cos t)\cos t\\ &=r\int\limits_L r+y_0\sin t+x_0\cos t\\ &=r^2t+x_0\sin t-y_0\cos t \end{aligned} \]

然后把圓弧的輪廓線搞出來做曲線積分,求和就可以了

順便這樣例太涼心了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1005;const double Pi=acos(-1.0);
struct Point{
    int x,y;
    inline Point(){}
    inline Point(R int xx,R int yy):x(xx),y(yy){}
    inline Point operator +(const Point &b)const{return Point(x+b.x,y+b.y);}
    inline Point operator -(const Point &b)const{return Point(x-b.x,y-b.y);}
    inline bool operator <(const Point &b)const{return x<b.x||(x==b.x&&y<b.y);}
    inline bool operator ==(const Point &b)const{return x==b.x&&y==b.y;}
    inline double norm(){return sqrt(x*x+y*y);}
};
struct Cir{
    Point p;int r;
    inline bool operator <(const Cir &b)const{return p<b.p||p==b.p&&r<b.r;}
    inline bool operator ==(const Cir &b)const{return p==b.p&&r==b.r;}
    inline double oint(R double t1,R double t2){
        return r*(r*(t2-t1)+p.x*(sin(t2)-sin(t1))-p.y*(cos(t2)-cos(t1)));
    }
}c[N];
pair<double,int>st[N<<1];int n;double res;
double calc(int id){
    int top=0,cnt=0;
    fp(i,1,n)if(i!=id){
        double dis=(c[i].p-c[id].p).norm();
        if(c[id].r+dis<=c[i].r)return 0;
        if(c[i].r+dis<=c[id].r||c[i].r+c[id].r<=dis)continue;
        double del=acos((c[id].r*c[id].r+dis*dis-c[i].r*c[i].r)/(2*c[id].r*dis));
        double ang=atan2(c[i].p.y-c[id].p.y,c[i].p.x-c[id].p.x);
        double l=ang-del,r=ang+del;
        if(l<-Pi)l+=2*Pi;if(r>=Pi)r-=2*Pi;
        if(l>r)++cnt;
        st[++top]=make_pair(l,1),st[++top]=make_pair(r,-1);
    }
    st[0]=make_pair(-Pi,0),st[++top]=make_pair(Pi,0);
    sort(st+1,st+1+top);
    double res=0;
    for(R int i=1;i<=top;cnt+=st[i++].second)
        if(!cnt)res+=c[id].oint(st[i-1].first,st[i].first);
    return res;
}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d",&n);
    fp(i,1,n)scanf("%d%d%d",&c[i].p.x,&c[i].p.y,&c[i].r);
    sort(c+1,c+1+n),n=unique(c+1,c+1+n)-c-1;
    fp(i,1,n)res+=calc(i);
    printf("%.3lf\n",res*0.5);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM