我是二分 + 并查集。 并查集是枚举任意两点, 如果距离够,就把他们的行连起来, 最后以 0 是否可以走到 n 来判断是否封锁, 但不知道为什么只得了 30 分,其他全 WA。
感觉思路错了,但想不到 hack 数据。
#include <cstdio>
#include <numeric>
#include <cmath>
#include <algorithm>
namespace Use{
using std::iota;
using std::sqrt;
using std::max;
using std::min;
using std::fill;
}
using namespace Use;
inline void read(int& x){
bool f=1;x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=!f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=(f?x:-x);
}
const int N=1000,M=805;
const double eps=1e-4,Inf=0x3f3f3f3f;
int n,m,x[M],y[M],f[N],maxn_x,maxn_y,minn_x=Inf,minn_y=Inf;
double maxn,dis[N][N];
double L(const int& x1,const int& y1,const int& x2,const int& y2){ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); }
void Read(){
read(n);read(m);
for(int i=1;i<=m;++i){
read(x[i]);read(y[i]);
//printf("%d %d\n",x[i],y[i]);
maxn_x=max(maxn_x,x[i]);
maxn_y=max(maxn_y,y[i]);
minn_x=min(minn_x,x[i]);
minn_y=min(minn_y,y[i]);
}
maxn=L(minn_x,minn_y,maxn_x,maxn_y);
//printf("%.2lf\n",maxn);
}
int find_set(int v){
if(v!=f[v])
f[v]=find_set(f[v]);
return f[v];
}
void merge(int x,int y){
x=find_set(x);y=find_set(y);
if(x!=y)
f[x]=y;
}
bool Check(const double& base){
double len=base*2;
iota(f,f+n+1,0);
for(int i=1;i<=m;++i){
if(x[i]<=base)merge(0,x[i]);
if(n-x[i]<=base)merge(x[i],n);
for(int j=i+1;j<=m;++j){
if(dis[i][j]<=len)
merge(x[i],x[j]);
}
}
if(find_set(0)==find_set(n))return true;
else return false;
}
void ErFen(double l,double r){
double mid;
while(r-l>eps){
mid=(l+r)/2;
if(Check(mid))r=mid;
else l=mid;
}
printf("%.2lf",l);
}
int main(){
Read();
for(int i=1;i<=m;++i){
for(int j=i+1;j<=m;++j){
dis[j][i]=dis[i][j]=L(x[i],y[i],x[j],y[j]);
}
}
ErFen(1,maxn);
return 0;
}