极角排序+联通图——uva11529

弄了一天了,也不知道哪里有问题

留着再说吧

/*
构图:枚举每个点作为原点,把原点和每个圆的切点也加进去,极角排序,
    扫描时用一个数组记录当前在那些圆的角度范围内 
构造出图后求联通块个数 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 5005
typedef double db;
const db eps=1e-6;
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);}
struct point{
    db x,y;
    int color,id,flag;
    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 getP() const{return sign(y)==1||(sign(y)==0&&sign(x)>=0);}
    point turn90(){return (point){-y,x};}
    db abs(){return sqrt(x*x+y*y);}
    point unit(){db w=abs();return (point){x/w,y/w};}
}; 
db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;}
db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;}
int comp(point k1,point k2){
    if(k1.getP()==k2.getP())return sign(cross(k1,k2))>0;
    return k1.getP()<k2.getP();
}
struct circle{
    point o;
    db r;        
    int color;
};
vector<point> TangentCP(circle k1,point k2){// 求点到圆的切点,沿圆 k1 逆时针给出 
    db a=(k2-k1.o).abs(),b=k1.r*k1.r/a,c=sqrt(max((db)0.0,k1.r*k1.r-b*b));
    point k=(k2-k1.o).unit(),m=k1.o+k*b,del=k.turn90()*c;
    return {m-del,m+del};
} 

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

int f[N],tot,in[N],cnt;
vector<int>G[N];
void solve(int id){
    tot=cnt=0;
    memset(in,0,sizeof in);
    memset(f,0,sizeof f);
    
    for(int i=1;i<=n;i++)
        if(i!=id){
            pp[++tot]=p[i]-p[id];
            pp[tot].id=i;
        }
    for(int i=1;i<=m;i++){
        circle k1=c[i];
        k1.o=k1.o-p[id];
        vector<point> v=TangentCP(k1,(point){0,0});
        if(sign(cross(v[0],v[1]))<0)
            swap(v[0],v[1]);
        pp[++tot]=v[0];
        pp[tot].color=i;
        pp[tot].flag=1;
        pp[++tot]=v[1];
        pp[tot].color=i;
        pp[tot].flag=0;
    }
    
    sort(pp+1,pp+1+tot,comp);
    for(int i=1;i<=tot;i++)pp[i+tot]=pp[i];
        
    for(int i=1;i<=tot*2;i++){
        if(pp[i].color==0){
            if(cnt!=0)f[pp[i].id]=1;
        }
        else {
            int color=pp[i].color;
            if(in[color]==1){
                if(pp[i].flag==0)
                    in[color]=0,cnt--;
            }
            else if(pp[i].flag==1)
                in[color]=1,cnt++;
        }
    }
    for(int i=1;i<=n;i++)
        if(!f[i]){
            G[i].push_back(id);
            G[id].push_back(i);
        }
}

int vis[N],ans;
void dfs(int u){
    vis[u]=1;
    for(auto v:G[u])
        if(!vis[v])dfs(v);
}

int main(){
    int t;cin>>t;
    while(t--){
        memset(vis,0,sizeof vis);
        ans=0;
        
        cin>>n>>m;
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
        for(int i=1;i<=m;i++)scanf("%lf%lf%lf",&c[i].o.x,&c[i].o.y,&c[i].r);
        
        if(m==0){
            puts("0");continue; 
        }
        
        for(int i=1;i<=n;i++)
            solve(i);//以i为原点 
        
        for(int i=1;i<=n;i++)
            if(!vis[i])++ans,dfs(i);
        cout<<ans-1<<'\n';
    }
}
/*
3
5 4
0 0
2 2
2 -2
-2 2
-2 -2
2 0 1
0 2 1
0 -2 1
1 1 0.5
4
1
0.9 0.9
0.9 -0.9
-0.9 0.9
-0.9 -0.9
0 0 1

5 2
0 0
2 -2
-2 2
1.9 1.9
-1.9 -1.9
1 1 1
-1 -1 1


*/

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/12337305.html