|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef pair<int, int> PII;
|
|
|
#define x first
|
|
|
#define y second
|
|
|
|
|
|
const int N = 510, M = N * N / 2; // C(n,2)
|
|
|
int n, k;
|
|
|
|
|
|
struct Edge {
|
|
|
int a, b;
|
|
|
double c;
|
|
|
const bool operator<(const Edge &t) const {
|
|
|
return c < t.c;
|
|
|
}
|
|
|
} edge[M];
|
|
|
int el;
|
|
|
|
|
|
// 每个村庄的坐标
|
|
|
PII q[M];
|
|
|
|
|
|
// 欧几里得距离
|
|
|
double get_dist(PII a, PII b) {
|
|
|
int x = a.x - b.x, y = a.y - b.y;
|
|
|
return sqrt(x * x + y * y);
|
|
|
}
|
|
|
|
|
|
// 并查集
|
|
|
int p[N];
|
|
|
int find(int x) {
|
|
|
if (p[x] != x) p[x] = find(p[x]);
|
|
|
return p[x];
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
cin >> n >> k; // 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 = i + 1; j < n; j++)
|
|
|
edge[el++] = {i, j, get_dist(q[i], q[j])}; // 因为是一个无向图,所以我们取一半就可以了
|
|
|
// 之所以取一半,其实也是为了配合后面的 cnt--,因为cnt--的现实含义是两个点连接上了,家族数量减少了1个
|
|
|
// 如果这里不是取一半,那么后面就需要cnt-=2, 哈哈,就问你是不是懵~
|
|
|
|
|
|
// 边权由小到大排序
|
|
|
sort(edge, edge + el);
|
|
|
|
|
|
// 并查集初始化
|
|
|
for (int i = 0; i < n; i++) p[i] = i;
|
|
|
|
|
|
int cnt = n; // 剩余的连通块数量
|
|
|
double res = 0;
|
|
|
|
|
|
// 原则:长的用卫星,短的用无线电收发机
|
|
|
// 合并完之后,正好剩下k个连通块,停止,每个连通块上安装卫星即可全面通讯
|
|
|
|
|
|
// 给原图的节点中n - k个节点生成一棵最小生成树
|
|
|
for (int i = 0; i < el; i++) { // 枚举每条边
|
|
|
if (cnt == k) break; // 剩余点数为k时停止, 在这k个点上建立卫星站
|
|
|
int a = edge[i].a, b = edge[i].b;
|
|
|
double c = edge[i].c;
|
|
|
a = find(a), b = find(b);
|
|
|
if (a != b) {
|
|
|
p[a] = b;
|
|
|
res = c; // 不停的记录参数d的上限
|
|
|
cnt--; // 连通块数量-1
|
|
|
}
|
|
|
}
|
|
|
printf("%.2lf\n", res);
|
|
|
return 0;
|
|
|
}
|