判断最小生成树是否唯一,可以证明如果MST不唯一,必然是由于有两条边的权相等(反过来不成立),那么在第一次求MST时可以标记这类边,然后逐一去掉重新求MST,看是否和之前的相等。
/* 判断最小生成树是否唯一, kruskal */ # include <stdio.h> # include <stdlib.h> # define N 105 # define M 5005 int n, m; int p[N]; int r[M], u[M], v[M], w[M]; char h[M], ud[M], pi[M]; int find(int x) {return x==p[x] ? x:(p[x] = find(p[x]));} int cmp(const void *x, const void *y) { int xx = *(int *)x, yy = *(int *)y; return w[xx] - w[yy]; } int kruskal(char bj) { int i, ret = 0, e, x, y; for (i = 1; i <= n; ++i) p[i] = i; for (i = 1; i <= m; ++i) if (h[e = r[i]]) { x = find(u[e]), y = find(v[e]); if (x != y) { p[x] = y; ret += w[e]; if (!bj && pi[e]) ud[e] = 1; } } return ret; } void solve(void) { int i, ans; for (i = 1; i <= m; ++i) { pi[i] = ud[i] = 0; r[i] = i, h[i] = 1; } qsort(r+1, m, sizeof(r[0]), cmp); for (i = 2; i <= m; ++i) if (w[r[i]] == w[r[i-1]]) pi[r[i]] = pi[r[i-1]] = 1; ans = kruskal(0); for (i = 1; i <= m; ++i) if (ud[i]) { h[i] = 0; if (ans == kruskal(1)) { puts("Not Unique!"); return ; } h[i] = 1; } printf("%d\n", ans); } void init(void) { int i; scanf("%d%d", &n, &m); for (i = 1; i <= m; ++i) scanf("%d%d%d", &u[i], &v[i], &w[i]); } int main() { int T; scanf("%d", &T); while (T--) { init(); solve(); } return 0; }
COJ 的题目排列怎么乱了,以前的题很多都找不到了,包括有一道(幻想乡的路?)也是要判断MST是否唯一。