平面欧拉公式——zoj2589

V-E+R=X+1:

 V:顶点数

 E:边数

 R:隔离的面数

 X:连通图数量

对于圆来说:V=E=0, 当两圆相交时,V+2,E+4,两圆相切时V+1,E+2

圆的边数E=圆上点数

#include<bits/stdc++.h>
using namespace std;
#define N 100005

typedef double db;
const db eps=1e-10;
const db pi=acos(-1);
int sign(db k){
    if (k>eps) return 1; else if (k<-eps) return -1; return 0;
}
int cmp(db k1,db k2){return sign(k1-k2);}
int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内 
struct point{
    db x,y;
    point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};}
    point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};}
    point operator * (db k1) const{return (point){x*k1,y*k1};}
    point operator / (db k1) const{return (point){x/k1,y/k1};}
    int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;}
    bool operator < (const point k1) const{
        int a=cmp(x,k1.x);
        if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1;
    }
    point unit(){db w=abs(); return (point){x/w,y/w};}
    db abs(){return sqrt(x*x+y*y);}
    db abs2(){return x*x+y*y;}
    db dis(point k1){return ((*this)-k1).abs();}
    point turn90(){return (point){-y,x};}
};
struct circle{
    point o;db r;
};
int checkposCC(circle k1,circle k2){// 返回两个圆的公切线数量
    if (cmp(k1.r,k2.r)==-1) swap(k1,k2);
    db dis=k1.o.dis(k2.o);  int w1=cmp(dis,k1.r+k2.r),w2=cmp(dis,k1.r-k2.r);
    if (w1>0) return 4; else if (w1==0) return 3; else if (w2>0) return 2; 
    else if (w2==0) return 1; else return 0;
}
vector<point> getCC(circle k1,circle k2){// 求两圆交点,沿圆 k1 逆时针给出 , 相切给出两个 
    int pd=checkposCC(k1,k2); if (pd==0||pd==4) return {};
    db a=(k2.o-k1.o).abs2(),cosA=(k1.r*k1.r+a-k2.r*k2.r)/(2*k1.r*sqrt(max(a,(db)0.0)));
    db b=k1.r*cosA,c=sqrt(max((db)0.0,k1.r*k1.r-b*b));
    point k=(k2.o-k1.o).unit(),m=k1.o+k*b,del=k.turn90()*c;
    return {m-del,m+del};
} 

point p[N];
circle c[N];
int n,cnt[N],tot,m;

int F[N];
int find(int x){
    return F[x]==x?x:F[x]=find(F[x]);
}

int main(){
    int t;cin>>t;
    while(t--){
        tot=m=0;
        
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>c[i].o.x>>c[i].o.y>>c[i].r;
        for(int i=1;i<=n;i++)F[i]=i;
        
        int X=n;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                    vector<point> v=getCC(c[i],c[j]);
                    if(v.size()==0 || v.size() && v[0]==v[1])continue;
                    for(auto pp:v)
                        p[++tot]=pp;
                    if(find(i)!=find(j)){
                        X--;
                        F[find(i)]=find(j);    
                    }
                }
        }
        
        //去重 
        sort(p+1,p+1+tot);
        m=0;
        if(tot)m=1;
        for(int i=2;i<=tot;i++)
            if(!(p[i]==p[i-1]))
                p[++m]=p[i];
        
        int V=m,E=0;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++)
                if(sign(p[i].dis(c[j].o)-c[j].r)==0)E++;
        }

        cout<<1+X-V+E<<'\n';
    }
}

 

posted on 2020-02-23 20:49  zsben  阅读(429)  评论(0编辑  收藏  举报

导航