题目链接:
https://vjudge.net/problem/POJ-1679
题目大意:
给定一个无向连通网,判断最小生成树是否唯一。
思路:
(1)对图中的每条边,扫描其他边,如果存在相同权值的边,对该边做标记。
(2)然后用kruskal算法或者prim算法求MST(标记MST中的边)
(3)求得MST后,如果MST中未包含做了标记的边,那么MST唯一。
MST中不包含未标记的边,说明MST中没有那些权值相同的边,用kruskal算法可知,该最小生成树肯定唯一。
(4)如果包含标记的边,依次去掉这些边,再求MST,如果所求的MST权值和之前的MST权值一样说明最小生成树不唯一,反之,则唯一。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #include<stack> 8 #include<map> 9 #include<sstream> 10 using namespace std; 11 typedef long long ll; 12 const int maxn = 1e5 + 10; 13 const int INF = 1 << 30; 14 int dir[4][2] = {1,0,0,1,-1,0,0,-1}; 15 int T, n, m, x; 16 bool first; 17 struct edge 18 { 19 int u, v, w; 20 bool used, equal, del;//used表示是否在MST中,equal表示边是否是相等,del表示求MST中删除的边 21 bool operator <(const edge& a)const 22 { 23 return w < a.w; 24 } 25 }; 26 edge a[maxn]; 27 int par[600], high[600]; 28 //初始化n个元素 29 void init(int n) 30 { 31 for(int i = 0; i < n; i++) 32 { 33 par[i] = i; 34 high[i] = 0; 35 } 36 } 37 //查询树的根 38 int Find(int x) 39 { 40 return par[x] == x ? x : par[x] = Find(par[x]);//路径压缩 41 } 42 void unite(int x, int y) 43 { 44 x = Find(x); 45 y = Find(y); 46 if(x == y)return; 47 if(high[x] < high[y])par[x] = y;//y的高度高,将x的父节点设置成y 48 else 49 { 50 par[y] = x; 51 if(high[x] == high[y])high[x]++; 52 } 53 } 54 int kruskal(int n, int m)//点数n,边数m 55 { 56 int sum_mst = 0;//mst权值 57 int num= 0;//已经选择的边的边数 58 sort(a, a + m);//边进行排序 59 init(n);//初始化并查集 60 for(int i = 0; i < m; i++) 61 { 62 int u = a[i].u; 63 int v = a[i].v; 64 if(a[i].del)continue; 65 if(Find(u - 1) != Find(v - 1))//图最开始的下标是1,并查集是0 66 { 67 //printf("%d %d %d\n", u, v, a[i].w); 68 sum_mst += a[i].w; 69 num++; 70 unite(u - 1, v - 1); 71 if(first)a[i].used = 1;//标记第一次MST的边 72 } 73 if(num >= n - 1)break; 74 } 75 //printf("weight of mst is %d\n", sum_mst); 76 return sum_mst; 77 } 78 int main() 79 { 80 cin >> T; 81 while(T--) 82 { 83 cin >> n >> m; 84 for(int i = 0; i < m; i++) 85 { 86 cin >> a[i].u >> a[i].v >> a[i].w; 87 a[i].used = a[i].equal = a[i].del = 0; 88 } 89 sort(a, a + m); 90 for(int i = 0; i < m; i++)//标记权值相同的边 91 { 92 int j = i + 1; 93 for(; j < m; j++) 94 { 95 if(a[j].w == a[i].w)a[i].equal = a[j].equal = 1; 96 else break; 97 } 98 i = j - 1; 99 } 100 first = 1; 101 int mst1 = kruskal(n, m); 102 first = 0; 103 int flag = 0; 104 for(int i = 0; i < m; i++) 105 { 106 if(a[i].used && a[i].equal)//依次删除第一次MST中相等的边,再次求MST 107 { 108 a[i].del = 1; 109 int mst2 = kruskal(n, m); 110 if(mst1 == mst2) 111 { 112 flag = 1; 113 cout<<"Not Unique!"<<endl; 114 break; 115 } 116 a[i].del = 0;//删除的标记清除 117 } 118 } 119 if(!flag)cout<<mst1<<endl; 120 } 121 return 0; 122 }