题意:航海线上有很多前哨需要通信,如果两个前哨各装了一个卫星,那么不用关心位置就可以相互通信,否则需要建造一个广播,能广播一定的范围来通信,广播距离越长花费越高,条件给出了前哨的坐标位置和卫星的数量,问广播范围最小是多少。
题解:最小生成树问题,先用kruskal算法把结点连通情况得出,然后将这些选出的边从大到小排序,卫星的数量m减一就是在选出最长的m - 1条边安装完卫星之后剩下的边中,距离最长的那条边就是广播的最小值,以保证其他被选出的边也能通信。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 505;
const double INF = 10000000000000;
struct Point {
int x, y;
}p[N];
struct Edge {
int u, v;
double l;
}e[N * N];
int t, n, m, parent[N], num;
int cmp(Edge a, Edge b) {
return a.l < b.l;
}
int cmp2(int a, int b) {
return e[a].l > e[b].l;
}
int get_parent(int x) {
return x == parent[x] ? x : get_parent(parent[x]);
}
bool Union(int x, int y) {
int px = get_parent(x);
int py = get_parent(y);
if (px != py) {
py[parent] = px;
return true;
}
return false;
}
int main() {
scanf("%d", &t);
while (t--) {
memset(e, 0, sizeof(e));
num = 0;
scanf("%d%d", &m, &n);
int a, b;
for (int i = 0; i < n; i++)
scanf("%d%d", &p[i].x, &p[i].y);
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) {
e[num].u = i;
e[num].v = j;
e[num++].l = sqrt((p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y));
}
sort(e, e + num, cmp);
for (int i = 0; i < n; i++)
parent[i] = i;
int temp[N * N], k = 0;
for (int i = 0; i < num; i++) {
if (Union(e[i].u, e[i].v))
temp[k++] = i;
}
sort(temp, temp + k, cmp2);
printf("%.2lf\n", e[temp[m - 1]].l);
}
return 0;
}