傳送門
解析:
最小生成樹的優秀做法。
建圖很妙啊,把所有點對之間建立距離爲權值的邊,然後所有點向頂部連權值爲距離的邊,向底部連權值爲的邊,然後求一個最小生成樹,將頂部和底部連在一起的邊的權值就是答案。
我解釋一下爲什麼這樣做是對的。
考慮我們現在有一艘直徑爲當前枚舉邊的飛碟,我們禁止它通過這條邊,如果它還可以飛到另一端,說明它穿過了一些權值大於它的直徑的邊,那麼它的直徑可以繼續增大。而上下連在一起,就形成了一個圍欄,它就永遠不可能到達另一端。此時它的直徑就已經達到了最大。
代碼:
#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;
}