判别MST是否唯一的例题。
POJ1679-The Unique MST
题意:给定图,求MST(最小生成树)是否唯一,唯一输出路径长,否则输出Not Unique!
题解:MST是否唯一取决于是否有两边权值相同(其中一条边在第一次求得的MST内,另一条在MST外)的情况。
如果存在这样的边,则需要逐次删除MST内的该边,再次求MST,如果此次求得的MST路长与第一次MST相同,则确实存在不唯一的MST
否则,一定不存在多条MST。
1 //Kruskal-判断MST是否唯一 2 //Time:0MS Memory:868K 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 9 #define MAX 101 10 11 struct Edge { 12 int u, v; 13 int w; 14 bool used; //First Used 15 bool del; //Kruskal是否不考虑此边 16 friend bool operator < (Edge e1, Edge e2) { return e1.w < e2.w; } 17 }e[MAX*MAX]; 18 19 int n, m; 20 bool first; //是否第一次求MST 21 int fa[MAX]; 22 int del[MAX*MAX], len; //须逐次删除的边 23 int minroad; //第一次MST结果 24 25 int Find(int x) 26 { 27 return fa[x] < 0 ? x : fa[x] = Find(fa[x]); 28 } 29 30 void Union(int r1, int r2) 31 { 32 r1 = Find(r1); 33 r2 = Find(r2); 34 int num = fa[r1] + fa[r2]; 35 if (fa[r1] < fa[r2]) 36 { 37 fa[r2] = r1; 38 fa[r1] = num; 39 } 40 else { 41 fa[r1] = r2; 42 fa[r2] = num; 43 } 44 } 45 46 bool kruskal() 47 { 48 memset(fa, -1, sizeof(fa)); 49 int num = 0; 50 int mind = 0; 51 for (int i = 0; i < m; i++) 52 { 53 if (e[i].del) continue; 54 if (Find(e[i].u) == Find(e[i].v)) continue; 55 Union(e[i].u, e[i].v); 56 if (first) { 57 minroad += e[i].w; 58 e[i].used = true; 59 } 60 mind += e[i].w; 61 if (mind > minroad) return true; 62 if (++num == n - 1) break; 63 } 64 65 return false; 66 } 67 68 int main() 69 { 70 int T; 71 scanf("%d", &T); 72 while (T--) 73 { 74 scanf("%d%d", &n, &m); 75 memset(e, 0, sizeof(e)); 76 for (int i = 0; i < m; i++) 77 scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w); 78 79 len = 0; 80 sort(e, e + m); 81 for (int i = 0; i < m; i++) 82 if (e[i].w == e[i + 1].w) 83 { 84 if(del[len-1] != i) del[len++] = i; 85 del[len++] = i + 1; 86 } 87 88 minroad = 0; 89 first = true; 90 kruskal(); 91 first = false; 92 93 bool unique = true; 94 for (int i = 0; i < len; i++) 95 { 96 if (!e[del[i]].used) continue; //使用过的才删除 97 e[del[i]].del = true; //删除 98 if (!kruskal()) 99 { 100 printf("Not Unique!\n"); 101 unique = false; break; 102 } 103 e[del[i]].del = false; //恢复 104 } 105 106 if (unique) 107 printf("%d\n", minroad); 108 } 109 110 111 112 return 0; 113 }