[并查集]JZOJ 5904 刺客信条
分析
连通性问题
如果底边和左边或者左边和右边连通和上边和底边连通或者上边和右边连通,则走不通
那么我们二分一下半径,每次n^2暴力每个点对,用并查集判断是否连通
然后最后,cmath信不得,我把sqrt去掉多拿了10分,把pow去掉又多拿了10分,就AC了
//#pragma GCC optimize(2) #include <iostream> #include <cstdio> #include <cmath> using namespace std; const int N=2e3+10; struct Point { double x,y; }a[N]; double x,y; int f[N],rk[N]; int n; int Get_F(int x) {return x==f[x]?x:f[x]=Get_F(f[x]);} void Merge(int x,int y) { int i=Get_F(x),j=Get_F(y); if (rk[i]<rk[j]) { rk[j]=max(rk[j],rk[i]+1); f[i]=j; } else { rk[i]=max(rk[i],rk[j]+1); f[j]=i; } } int main() { freopen("AC.in","r",stdin); freopen("AC.out","w",stdout); scanf("%lf%lf%d",&x,&y,&n); for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); double l=0,r=1e6,mid; while (r-l>1e-3) { mid=(l+r)/2.0; for (int i=1;i<=n+4;i++) f[i]=i,rk[i]=1; for (int i=1;i<=n-1;i++) for (int j=i+1;j<=n;j++) if ((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)<mid*mid*4.0) Merge(i,j); for (int i=1;i<=n;i++) { if (a[i].x<mid) Merge(i,n+1); if (a[i].y<mid) Merge(i,n+2); if (x-a[i].x<mid) Merge(i,n+3); if (y-a[i].y<mid) Merge(i,n+4); } int f1=Get_F(n+1),f2=Get_F(n+2),f3=Get_F(n+3),f4=Get_F(n+4); if (f1==f2||f1==f3||f2==f4||f3==f4) r=mid; else l=mid+1e-3; } printf("%.2lf",mid); }
在日渐沉没的世界里,我发现了你。