POJ 1679 The Unique MST
题意:给一个图,判断它的最小生成树唯一不唯一。
解法:首先,容易想到一个O(n^3)或者说O(m*n^2)的方法。就是首先,求一遍最小生成树,记权值和为x1,然后枚举最小生成树中的每一条边,在不用该边的情况下求出的最小生成树权值和为x2,若枚举到某条边的时候x1 = x2,则最小生成树不唯一。若全不相等,则唯一。
但是,觉得这个方法太慢了,上网搜索了一下搜到了这篇文章,https://www.byvoid.com/blog/2-sp-mst,求次小生成树。(这道题相当于判定最小生成树和次小生成树权值和是否相等)
上面那篇文章的方法,中心思想在于:枚举每条不在最小生成树中的边,若将它加入最小生成树,一定会生成环,去掉环中的最长边,则是新的最小生成树,若去掉的边权值和加入的边权值相同,则最小生成树和次小生成树权值和相同。当然,这样写的话,时间复杂度也可能打到O(n^3),但是,基于这个思想,能有O(n^2 + m)的写法。
O(n^2+m)的写法为,从每个节点i遍历整个最小生成树,定义f[j]为最小生成树上从i到j的边中权值最大边的权值,然后遍历所有不在最小生成树中的边(i, k)比较w(i, k)和f[k]的大小,若相等则最小生成树不唯一。
tag:MST,次小生成树
解法一O(n^3):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-12-03 21:27 4 * File Name: G-POJ-1679.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 11 using namespace std; 12 13 #define CLR(x) memset(x, 0, sizeof(x)) 14 struct Pat{ 15 int s, e, w; 16 }; 17 18 int n, m, f[10005]; 19 bool v[10005]; 20 Pat p[10005]; 21 22 bool cmp(Pat a, Pat b) 23 { 24 return a.w < b.w; 25 } 26 27 void init() 28 { 29 scanf ("%d%d", &n, &m); 30 for (int i = 0; i < m; ++ i) 31 scanf ("%d%d%d", &p[i].s, &p[i].e, &p[i].w); 32 sort (p, p+m, cmp); 33 CLR (v); 34 } 35 36 int find(int x) 37 { 38 if (x != f[x]) f[x] = find(f[x]); 39 return f[x]; 40 } 41 42 int kruskal(int x) 43 { 44 for (int i = 0; i < n; ++ i) 45 f[i] = i; 46 47 int cost = 0; 48 for (int i = 0; i < m; ++ i) if (i != x){ 49 int t1 = find(p[i].s), t2 = find(p[i].e); 50 if (t1 != t2){ 51 cost += p[i].w; 52 f[t1] = t2; 53 if (x == -1) v[i] = 1; 54 } 55 } 56 57 int tmp; 58 for (int i = 0; i < n; ++ i){ 59 if (!i) tmp = find(i); 60 else if (tmp != find(i)) return -1; 61 } 62 63 return cost; 64 } 65 66 int main() 67 { 68 int T; 69 scanf ("%d", &T); 70 while (T--){ 71 init(); 72 int ans = kruskal(-1); 73 bool ok = 1; 74 for (int i = 0; i < m; ++ i) if (v[i]){ 75 int tmp = kruskal(i); 76 if (tmp == ans){ 77 ok = 0; 78 break; 79 } 80 } 81 if (ok) printf ("%d\n", max(ans, 0)); 82 else printf ("Not Unique!\n"); 83 } 84 return 0; 85 }
解法二O(n^2+m):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-12-04 19:35 4 * File Name: G-POJ-1679-2.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 #include <vector> 11 12 using namespace std; 13 14 #define CLR(x) memset(x, 0, sizeof(x)) 15 #define CLR1(x) memset(x, -1, sizeof(x)) 16 #define PB push_back 17 18 struct Pat{ 19 int s, e, w; 20 }; 21 22 int n, m; 23 Pat p[10005]; 24 bool vis[105][105]; 25 int d[105][105], f[105]; 26 int cnt[105]; 27 vector<int> nod[105]; 28 29 bool cmp(Pat a, Pat b) 30 { 31 return a.w < b.w; 32 } 33 34 void init() 35 { 36 CLR (vis); 37 CLR1 (d); 38 39 scanf ("%d%d", &n, &m); 40 for (int i = 0; i < m; ++ i){ 41 scanf ("%d%d%d", &p[i].s, &p[i].e, &p[i].w); 42 -- p[i].s; -- p[i].e; 43 d[p[i].s][p[i].e] = p[i].w; 44 d[p[i].e][p[i].s] = p[i].w; 45 } 46 sort (p, p+m, cmp); 47 48 for (int i = 0; i < n; ++ i) 49 nod[i].clear(); 50 } 51 52 int find(int x) 53 { 54 if (x != f[x]) f[x] = find(f[x]); 55 return f[x]; 56 } 57 58 int kruskal() 59 { 60 for (int i = 0; i < n; ++ i) 61 f[i] = i; 62 63 int cost = 0; 64 for (int i = 0; i < m; ++ i){ 65 int s = p[i].s, e = p[i].e, w = p[i].w; 66 int t1 = find(s), t2 = find(e); 67 if (t1 != t2){ 68 f[t1] = t2; 69 cost += w; 70 nod[s].PB (e); 71 nod[e].PB (s); 72 vis[e][s] = vis[s][e] = 1; 73 } 74 } 75 76 int tmp; 77 for (int i = 0; i < n; ++ i){ 78 if (!i) tmp = find(i); 79 else if (tmp != find(i)) return -1; 80 } 81 return cost; 82 } 83 84 void dfs(int x, int ma) 85 { 86 if (cnt[x] != -1) return; 87 88 cnt[x] = ma; 89 int sz = nod[x].size(); 90 for (int i = 0; i < sz; ++ i) 91 if (cnt[nod[x][i]] == -1) 92 dfs (nod[x][i], max(d[x][nod[x][i]], ma)); 93 } 94 95 int main() 96 { 97 int T; 98 scanf ("%d", &T); 99 while (T--){ 100 init(); 101 int ans = kruskal(); 102 if (ans == -1){ 103 printf ("0\n"); 104 continue; 105 } 106 bool ok = 0; 107 for (int i = 0; i < n; ++ i){ 108 CLR1 (cnt); 109 dfs (i, 0); 110 111 for (int j = 0; j < n; ++ j) if (i != j && !vis[i][j]) 112 if (cnt[j] == d[i][j]) ok = 1; 113 } 114 if (!ok) printf ("%d\n", ans); 115 else printf ("Not Unique!\n"); 116 } 117 return 0; 118 }
------------------------------------------------------------------
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。