题目大意:
南极有n个科研站, 要把这些站用卫星或者无线电连接起来,使得任意两个都能直接或者间接相连。任意两个都有安装卫星设备的,都可以直接通过卫星通信,不管它们距离有多远。 而安装有无线电设备的两个站,距离不能超过D。 D越长费用越多。
现在有s个卫星设备可以安装,还有足够多的无线电设备,求一个方案,使得费用D最少(D取决与所有用无线电通信的花费最大的那条路径)。
分析与总结:
很自然的想到求最小生成树,然后为了使得D费用最少,就要让其中路径最长的那些用来安装卫星。 s个通信卫星可以安装s-1条最长的那些路径。 那么, 最小生成树中第p-s大的路径长度就是D。
只需要求出最小生成树上的所有路径长度,排好序,边得到答案。(借鉴)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define N 250005 using namespace std; struct state{ int l, r; double value; }s[N]; int n, m, cnt, f[N], x[N], y[N]; double ans; bool cmp(const state& a, const state& b) { return b.value - a.value > 1e-9; } int getFather(int x) { x == f[x] ? x : f[x] = getFather(f[x]); } void init() { cnt = 0; memset(x, 0, sizeof(x)); memset(y, 0, sizeof(y)); scanf("%d %d", &n, &m); for (int i = 0; i < m; i++) { f[i] = i; scanf("%d %d", &x[i], &y[i]); for (int j = 0; j < i; j++) { s[cnt].value = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])); s[cnt].l = i; s[cnt].r = j; cnt++; } } sort(s, s + cnt, cmp); } void kruskal() { int t = m - n - 1; for (int i = 0; i < cnt; i++) { int p = getFather(s[i].l); int q = getFather(s[i].r); if (p != q) { ans = s[i].value; if (t) { t--; f[q] = p; } else return; } } } int main() { int cas; scanf("%d", &cas); while (cas--) { init(); kruskal(); printf("%.2lf\n", ans); } return 0; }