• 极角排序经典题+联通图——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<<'
    ';
        }
    }
    /*
    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
    
    
    */
  • 相关阅读:
    eclipse FilteredTree
    Windows API高精度计时 C#版
    循环中响应消息,避免循环时UI线程被阻塞
    Linux rpm 包制作 使用 rpmbuild
    利用Windows API实现精确计时
    C++显示选择文件夹对话框
    android AsyncTask
    [转]Android 动画学习笔记
    eclipse 中导入android 工程时出错:The method of type must override a superclass method 解决方式
    Android 自定义对话框
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12337305.html
Copyright © 2020-2023  润新知