本题采用公共祖先的写法,有卫星就的村庄不需要考虑距离,所以我们可以排序,将距离远的村庄排在后面,先枚举距离近的。
定义一个结构体,存储两个村庄的编号和距离,存储时枚举用两个for循环,每次i在前,只需要存储比i小的j,这样保证不会多存。
从小到大枚举,接下来每多枚举一个点,就少一个村庄,记录当下距离为res,定义cnt = n,每次减减,如果cnt <= 卫星树,则符合了,输出之前枚举的最大的res
C++ 代码
//找一个最小的d,使得将所有权值大于d的边删去之后,
//整个图形的连通块的个数不超过k
//1.将所有边按权从小到大排序
//2.从小到大扫描所有边,一次将没有合并的点集合并
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 510, M = N * N / 2;
int n, k, m;
struct Edge
{
int a, b;
double w;
bool operator < (const Edge &t) const
{
return w < t.w;
}
}e[M];
PII q[M];
int p[N];
double get_dist(PII u, PII v)
{
double dx = u.x - v.x;
double dy = u.y - v.y;
return sqrt(dx * dx + dy * dy);
}
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> k;
for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < i; j ++ )
e[m ++ ] = {i, j, get_dist(q[i], q[j])};
sort(e, e + m);
for (int i = 0; i < n; i ++ ) p[i] = i;
int cnt = n;
double res = 0;
for (int i = 0; i < m; i ++ )
{
if (cnt <= k) break;
int a = find(e[i].a);
int b = find(e[i].b);
if (a != b)
{
res = e[i].w;
p[a] = b;
cnt -- ;
}
}
printf("%.2f", res);
}