• BZOJ2178: 圆的面积并(格林公式)


    题面

    传送门

    题解

    好神仙……

    先给几个定义

    平面单连通区域:设(D)是平面内一区域,若属于(D)内任一简单闭曲线的内部都属于(D),则称(D)为单连通区域。通俗地说,单连通区域是没有“洞”的区域。

    正方向:当(xOy)平面上的曲线起点与终点重合时,则称曲线为闭曲线。设平面的闭曲线L围成平面区域(D),并规定当一个人沿闭曲线(L)环行时,区域(D)总是位于此人的左侧,称此人行走方向为曲线L关于区域(D)的正方向,反之为负方向。

    格林公式:设(D)是一个平面单连通区域,(L)是它取正向的轮廓线(分段光滑),(P,Q)(D)上具有一阶连续偏导数,则有格林公式

    [intintlimits_Dleft({partial Qover partial x}-{partial Pover partial y} ight)mathrm dxmathrm dy=ointlimits_LPmathrm dx+Qmathrm dy ]

    关于那个(oint)就是一个有方向的(int),直接当成(int)看就好了

    回到本题,我们令(Q=x,P=-y),我们要求的东西就是

    [intintlimits_D1mathrm dxmathrm dy={1over 2}ointlimits_L-ymathrm dx+xmathrm dy ]

    这样转化之后,我们就可以把圆的面积转化成跟轮廓线有关的计算了

    因为圆弧上(x,y)很麻烦,我们用角度来表示它

    [egin{aligned} intlimits_L-ymathrm dx+xmathrm dy &=intlimits_L-(y_0+rsin t)mathrm d(x_0+rcos t)+(x_0+rcos t)mathrm d(y_0+rsin t)\ &=intlimits_L(y_0+rsin t)(rsin t)+(x_0+rcos t)(rcos t)\ &=rintlimits_L(y_0+rsin t)sin t+(x_0+rcos t)cos t\ &=rintlimits_L r+y_0sin t+x_0cos t\ &=r^2t+x_0sin t-y_0cos 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
    ",res*0.5);
        return 0;
    }
    
  • 相关阅读:
    HDU 5033 Building --离线+单调栈
    HDU 5025 Saving Tang Monk --BFS
    Codeforces Round #267 Div.2 D Fedor and Essay -- 强连通 DFS
    Codeforces Round #267 Div2 C George and Job --DP
    POJ 3150 Cellular Automaton --矩阵快速幂及优化
    TopCoder SRM 633 Div.2 500 Jumping
    HDU 4998 Rotate --几何
    一些语言方面的技巧
    HDU 5017 Ellipsoid 模拟退火第一题
    HDU 5015 233 Matrix --矩阵快速幂
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10750156.html
Copyright © 2020-2023  润新知