传送门
解析:
最小生成树的优秀做法。
建图很妙啊,把所有点对之间建立距离为权值的边,然后所有点向顶部连权值为距离的边,向底部连权值为 L − y L-y L−y的边,然后求一个最小生成树,将顶部和底部连在一起的边的权值就是答案。
我解释一下为什么这样做是对的。
考虑我们现在有一艘直径为当前枚举边的飞碟,我们禁止它通过这条边,如果它还可以飞到另一端,说明它穿过了一些权值大于它的直径的边,那么它的直径可以继续增大。而上下连在一起,就形成了一个围栏,它就永远不可能到达另一端。此时它的直径就已经达到了最大。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
re bool f=0;
while(!isdigit(c=gc()))if(c=='-')f=1;num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return f?-num:num;
}
cs int N=502;
struct edge{
int u,v;
double w;
friend bool operator<(cs edge &a,cs edge &b){
return a.w<b.w;
}
}E[N*N];int ecnt;
inline void addedge(int u,int v,double w){
E[++ecnt]=(edge){u,v,w};
}
int fa[N];
inline int getfa(int u){
while(u^fa[u])u=fa[u]=fa[fa[u]];
return u;
}
int n,L;
int x[N],y[N];
inline double dist(int i,int j){
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
signed main(){
n=getint();L=getint();
for(int re i=1;i<=n;++i){
fa[i]=i;
x[i]=getint();y[i]=getint();
for(int re j=1;j<i;++j)addedge(i,j,dist(i,j));
addedge(0,i,y[i]);
addedge(n+1,i,L-y[i]);
}
fa[n+1]=n+1;
sort(E+1,E+ecnt+1);
for(int re i=1;i<=ecnt;++i){
int u=getfa(E[i].u);
int v=getfa(E[i].v);
if(u==v)continue;
fa[v]=u;
if(getfa(0)==getfa(n+1)){
printf("%.3f",E[i].w);
return 0;
}
}
return 0;
}