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):

 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 }
View Code

解法二O(n^2+m):

  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 }
View Code

 

posted @ 2013-12-04 23:55  Plumrain  阅读(276)  评论(0编辑  收藏  举报