极角排序经典题+联通图——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 */