【题解】UVA1395 苗条的生成树 Slim Span

题目链接(洛谷)

题目大意

给出一个\(n\)个节点\(m\)条边的图,求所有生成树中最大边权与最小边权差最小的,输出它们的差值。

\(1\le n \le 100,1\le m\le \frac{n\times (n−1)}{2}\)

分析

用Kruskal求解最小生成树。每次枚举最小的那条边,然后Kruskal一遍,找到最大的边,更新答案。

实现

\((100pts,20ms)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include<bits/stdc++.h>

using namespace std;
const int N = 105, inf = 0x3f3f3f3f;
int n, m, fa[N], maxn, ans;
struct node {
int a, b, v;
} e[N * 1000];

int find(int x) {
if (fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}

bool merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return false;
if (x != y) {
fa[x] = y;
return true;
}
}

bool kru(int st) {
int cnt = 0;
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
maxn = -inf;
for (int i = st; i <= m; i++) {
if (merge(e[i].a, e[i].b)) {
maxn = e[i].v;
cnt++;
if (cnt == n - 1) return true;
}
}
return false;
}

bool cmp(node a, node b) {
return a.v < b.v;
}

void init() {
for (int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1, e + m + 1, cmp);
maxn = -inf;
ans = inf;
}

int main() {
while (cin >> n) {
cin >> m;
if (!n && !m) break;
for (int i = 1; i <= m; i++) {
cin >> e[i].a >> e[i].b >> e[i].v;
}
init();
for (int i = 1; i <= m; i++) {//枚举最小的边
if (kru(i)) {
ans = min(ans, maxn - e[i].v);
}
}
if (ans == inf) cout << "-1\n";
else cout << ans << "\n";
}
return 0;
}