Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 21646 | Accepted: 7661 |
Description
Input
Output
Sample Input
2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2
Sample Output
3
Not Unique!
Source
题目链接:http://poj.org/problem?id=1679
题目大意:判断最小生成树是否唯一
题目分析:对图中的每条边,扫瞄其他边,如果存在权值相同的边则标记,然后用Kruskal求最小生成树,如果该MST中未包含标记的边,则必唯一直接输出权值,否则依次去掉这些边再求MST,若两次求得的权值相同,则说明不唯一
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int const MAXN = 105; int const MAXM = 6000; int m, n; int fa[MAXN], rank[MAXN]; bool fir, flag; struct Edge { int u, v, w; bool equal, used, del; }e[MAXM]; bool cmp(Edge a, Edge b) { return a.w < b.w; } void UFset() { for(int i = 0; i <= n; i++) fa[i] = i; memset(rank, 0, sizeof(rank)); } int Find(int x) { return x == fa[x] ? x : fa[x] = Find(fa[x]); } void Union(int a, int b) { int r1 = Find(a); int r2 = Find(b); if(r1 == r2) return; if(rank[r1] > rank[r2]) fa[r2] = r1; else { fa[r1] = r2; if(rank[r1] == rank[r2]) rank[r1]++; } } int Kruskal() { int u, v; int num = 0, sum = 0; UFset(); for(int i = 0; i < m; i++) { if(e[i].del) continue; u = e[i].u; v = e[i].v; if(Find(u) != Find(v)) { sum += e[i].w; Union(u, v); num++; if(fir) e[i].used = true; } if(num == n - 1) break; } return sum; } int main() { int T, u, v, w; scanf("%d", &T); while(T--) { flag = false; scanf("%d %d", &n, &m); for(int i = 0; i < m; i++) { scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w); e[i].equal = e[i].used = e[i].del = false; } sort(e, e + m, cmp); for(int i = 0; i < m; i++) { for(int j = 0; j < m; j++) { if(i == j) continue; if(e[i].w == e[j].w) e[i].equal = true; } } fir = true; int w1 = Kruskal(), w2; fir = false; for(int i = 0; i < m; i++) { if(e[i].used && e[i].equal) { e[i].del = true; //删去这条边 w2 = Kruskal(); if(w1 == w2) { printf("Not Unique!\n"); flag = true; break; } e[i].del = false; } } if(!flag) printf("%d\n", w1); } }
POJ 1679 The Unique MST (Kruskal 判最小生成树是否唯一)
原文地址:http://blog.csdn.net/tc_to_top/article/details/43671975