POJ-1679 The Unique MST---判断最小生成树是否唯一

题目链接:

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 }

 

posted @ 2018-04-06 14:05  _努力努力再努力x  阅读(365)  评论(0编辑  收藏  举报