点我去A了这道题
感觉还是满有代表性的题,也不很难
第一想法是二分半径r,如何check?
当两个点的距离小于等于2r时就形成了一个整体
那我可以用并查集把他们合并。合并后拿新点再次开始枚举
如果某个点和新点距离小于2r我就再合并
结束后,看一下
Ⅰ.排序+并查集
其实m个点,点与点间只有m2个距离
为了方便,我们构造0点代表左边界,m+1点,并且每个点和左边界和有边界连边
那直接按照距离排序,从小到大把点对用并查集合并
什么时候0点和m+1点合并在一起了,什么时候就停下来
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
struct p{
int x,y; double d;
bool operator < (const p&tmp ) const{
return d<tmp.d;
}
}a[maxn]; int cnt=0,pre[maxn],n,m;
int find(int x){
return x==pre[x]?x:pre[x]=find(pre[x]);
}
void join(int q,int w){
pre[find(q)]=find(w);
}
double x[maxn],y[maxn];
double ju(int q,int w){
return sqrt( (x[q]-x[w])*(x[q]-x[w])+(y[q]-y[w])*(y[q]-y[w]) );
}
int main()
{
cin >> n >> m;
for(int i=1;i<=m;i++)
cin >> x[i] >> y[i];
for(int i=0;i<=m+1;i++) pre[i]=i;
for(int i=1;i<=m;i++)
{
a[++cnt]=(p){0,i,2*x[i]};
a[++cnt]=(p){m+1,i,2*(n-x[i])};
for(int j=i+1;j<=m;j++)
a[++cnt]=(p){i,j,ju(i,j)};
}
sort(a+1,a+1+cnt);
for(int i=1;i<=cnt;i++)
{
join(a[i].x,a[i].y);
if( find(0)==find(m+1) )
{
printf("%.2lf",a[i].d/2.0);
return 0;
}
}
}
Ⅱ.最短路或最小生成树
其实题目的本质就是要把0到n合并起来
那就从0到n跑最短路
路径的花费是路上最大的边权,边权是点间的距离/2
或者直接最小生成树也可以把0点和n连接起来