题意:给点一个无向图,求一个生成树使树中最大边与最小边的差的最小。
分析:并查集。把所有边排序,然后从小到大看,每次枚举一个边,将其权值作为下界,向右寻求一个上界,让上下界之间的边可以使得图连通。寻求过程中,是每次将一个边加入图中,判断图是否连通,不行则再加一条边,判断过程用并查集。找到没个下界对应的上界,找上下界差的最小值。
View Code
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int maxn = 105, maxm = maxn * maxn / 2, inf = 0x3f3f3f3f; struct Edge { int a, b, w; }edge[maxm]; int n, m; int father[maxn]; bool operator < (const Edge &a, const Edge &b) { return a.w < b.w; } void input() { for (int i = 0; i < m; i++) { int a, b, w; scanf("%d%d%d", &a, &b, &w); a--; b--; edge[i].a = a; edge[i].b = b; edge[i].w = w; } } int getanc(int a) { if (a == father[a]) return a; return father[a] = getanc(father[a]); } int cal(int l) { for (int i = 0; i < n; i++) father[i] = i; int i = l; int block_num = n; while (i < m && block_num > 1) { int a = getanc(edge[i].a); int b = getanc(edge[i].b); if (a != b) { block_num--; father[a] = b; } i++; } if (block_num > 1) return -1; return edge[i - 1].w - edge[l].w; } void work() { int ans = cal(0); if (ans == -1) { printf("-1\n"); return; } for (int i = 1; i < m; i++) { if (edge[i].w == edge[i - 1].w) continue; int temp = cal(i); if (temp == -1) break; ans = min(ans, temp); } printf("%d\n", ans); } int main() { //freopen("t.txt", "r", stdin); while (scanf("%d%d", &n, &m), n | m) { memset(edge, -1, sizeof(edge)); input(); sort(edge, edge + m); work(); } return 0; }