题意:航海线上有很多前哨需要通信,如果两个前哨各装了一个卫星,那么不用关心位置就可以相互通信,否则需要建造一个广播,能广播一定的范围来通信,广播距离越长花费越高,条件给出了前哨的坐标位置和卫星的数量,问广播范围最小是多少。

题解:最小生成树问题,先用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;
}