简单几何+并查集 —— 2015NAQ K
问题可以简化成, 最大能取到多少,使得前 个圆不能使左边界和右边界联通。
并查集维护圆与圆、圆与左右边界的联通性即可。
#include<bits/stdc++.h> using namespace std; #define N 505 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);} 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};} point turn(db k1){return (point){x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1)};} point turn90(){return (point){-y,x};} db abs(){return sqrt(x*x+y*y);} db abs2(){return x*x+y*y;} db dis(point k1){return ((*this)-k1).abs();} point unit(){db w=abs(); return (point){x/w,y/w};} }; int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);} 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;} db rad(point k1,point k2){return atan2(cross(k1,k2),dot(k1,k2));} struct circle{ point o; db r; int inside(point k){return cmp(r,o.dis(k));} }; int n; circle c[N]; point k1,k2,k3,k4; int F[N]; int find(int x){ return x==F[x]?x:F[x]=find(F[x]); } void bing(int u,int v){ int fu=find(u),fv=find(v); if(fu!=fv) F[fu]=fv; } int judge(int n){ for(int i=1;i<=n+2;i++)F[i]=i; for(int i=1;i<=n;i++){ if(c[i].o.x<c[i].r)bing(i,n+1);//圆和左边界相交 if(c[i].o.x+c[i].r>200)bing(i,n+2);//圆和右边界相交 for(int j=i+1;j<=n;j++) if(c[i].r+c[j].r>c[i].o.dis(c[j].o)) bing(i,j); } if(find(n+1)==find(n+2)) return 0; return 1; } int main(){ k1=(point){0.0,0.0}; k2=(point){200.0,0.0}; k3=(point){200.0,300.0}; k4=(point){0,300.0}; cin>>n; for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&c[i].o.x,&c[i].o.y,&c[i].r); int ans=0; for(int i=1;i<=n;i++){ if(judge(i))ans=i; else break; } cout<<ans<<'\n'; }