传送门
题解
这其实是个作图题,考试的时候把k全打成了n,emmm。。。
一看完题就能想到去年noip day2t1,但是要求最小距离最大的话,就很明显要用个二分了。
把上下左右四个边界都看作一个点,对于当前二分的最大距离,分情况讨论:
1. 从下边界能走到左边界;
2. 从下边界能走到上边界;
3. 从下边界能走到右边界;
4. 从上边界能走到右边界;
任意满足一种情况都是走不到的。所以每次check就用一个并查集维护联通性就可以了,时间O(n2logn)。
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #define maxn 2010 #define reg register using namespace std; const double eps=1e-5; int n,m,k,a,b,c,d,fa[maxn]; double dis[maxn][maxn],x[maxn],y[maxn]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void merge(int x,int y) { fa[find(x)]=find(y); } bool check(double w) { for(reg int i=1; i<=k+4; i++) fa[i]=i; for(reg int i=1; i<=k; i++) { if(w-x[i]>eps) merge(a,i);//这里按题意来说应该是>=但是加了判等后反而会wa?? if(w-y[i]>eps) merge(b,i); if(w-(n-x[i])>eps) merge(c,i); if(w-(m-y[i])>eps) merge(d,i); for(reg int j=i+1; j<=k; j++) if(w*2-dis[i][j]>eps || (w*2-dis[i][j]<eps && dis[i][j]-w*2<eps)) merge(i,j); } if(find(a)==find(b)) return true; if(find(a)==find(c)) return true; if(find(c)==find(d)) return true; if(find(b)==find(d)) return true; return false; } int main() { scanf("%d%d%d",&n,&m,&k); a=k+1,b=k+2,c=k+3,d=k+4; for(reg int i=1; i<=k; i++) scanf("%lf%lf",&x[i],&y[i]); for(reg int i=1; i<=k; i++)//预处理每个点对之间距离 for(reg int j=i+1; j<=k; j++) dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); double l=0,r=1000000; while(r-l>eps) { double mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } printf("%.2lf",l); return 0; }