极角排序经典题+联通图——uva11529

一道题弄了一整天。。

本题有一个坑:在每个圆覆盖的极角范围内,有的点因为离圆心近,还是不会被圆挡住,所以在判断圆能否挡住一个点时,还要再用点积判一下该点是否在切点,圆心,原点三角形内

收获:要慎重选择使用叉积进行排序还是直接用rad排序,前者精度高,后者实际用起来更加方便,本题要用到lower_bound,所以还是用rad方便一点

/*
构图:枚举每个点作为原点,把原点和每个圆的切点也加进去,极角排序,
    扫描时用一个数组记录当前在那些圆的角度范围内 
构造出图后求联通块个数 
*/
#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,rad;
    int color,id,flag;
    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 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){
    
}
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;
vector<int>G[N];
pair<db,int>rads[N];

void solve(int id){
    memset(f,0,sizeof f);
    tot=0;
    for(int i=id+1;i<=n;i++){
        point k=p[i]-p[id];
        rads[++tot]=make_pair(atan2(k.y,k.x),i);    
    }
    sort(rads+1,rads+tot+1);
    
    for(int i=1;i<=m;i++){
        point o=c[i].o;
        db rad=atan2((o-p[id]).y,(o-p[id]).x);
        db dist=(o-p[id]).abs();
        db delta=asin(c[i].r/dist);
        pair<db,int> L=make_pair(rad-delta,-1);
        pair<db,int> R=make_pair(rad+delta,-1);
        int pos=lower_bound(rads+1,rads+1+tot,L)-rads;
        for(int j=pos;j<=tot;j++){
            if(rads[j]>R)break;
            if(dot(p[id]-p[rads[j].second],o-p[rads[j].second])>=0) 
                f[rads[j].second]=1;
        } 
    }
    
    for(int i=id+1;i<=n;i++)if(f[i]==0){
        G[id].push_back(i);
        G[i].push_back(id);
    }
}

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);
        
        sort(p+1,p+1+n);
        
        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


*/

 

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

导航