题目大意:给定平面上的n个点,要求将这n个点划分为k个集合,使划分后任意两个集合中最近两点的距离的最大值最小,输出这个最小值
考虑这n个点之间所有的连边 我们要让长边保留 就尽量选取短边链接
于是就是求加入n-k条边的最小生成森林 由于输出下一个最小值 因此Kruskal加入第n-k+1条边时输出边权即可
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define M 1100
using namespace std;
struct point{
int x,y;
void Read()
{
scanf("%d%d",&x,&y);
}
}points[M];
struct edge{
int x,y;
double dis;
edge() {}
edge(int _,int __,double ___):
x(_),y(__),dis(___) {}
bool operator < (const edge &e) const
{
return dis < e.dis;
}
}edges[1001001];
int n,m,k;
double Distance(const point &p1,const point &p2)
{
return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) );
}
namespace Union_Find_Set{
int fa[M];
inline void Union(int x,int y)
{
fa[x]=y;
}
int Find(int x)
{
if(!fa[x]||fa[x]==x)
return fa[x]=x;
return fa[x]=Find(fa[x]);
}
}
double Kruskal(int temp)
{
using namespace Union_Find_Set;
int i;
sort(edges+1,edges+m+1);
for(i=1;i<=m;i++)
{
int x=Find(edges[i].x);
int y=Find(edges[i].y);
if(x==y) continue;
Union(x,y);
if(!--temp)
return edges[i].dis;
}
return 0;
}
int main()
{
int i,j;
cin>>n>>k;
for(i=1;i<=n;i++)
points[i].Read();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
edges[++m]=edge(i,j,Distance(points[i],points[j]) );
cout<<fixed<<setprecision(2)<<Kruskal(n-k+1)<<endl;
}