poj 1679 The Unique MST(次小生成树)

题意:判断最小生成树是否唯一。

分析:只需要判断最小生成树与次小生成树的总权值是否相等。

判断次小生成树的方法:

kruskal O(n^3):先求一次最小生成树,然后枚举去掉生成树中的边,再求n-1次最小生成树,去最小的一棵。

prim O(n^2):先求一次最小生成树,记录树上的边,并且保存每个环中的最大边,然后用一次DP枚举掉树上的边,更新生成树的权和,取最小值。

kruskal
  1 /*
  2 Author:Zhaofa Fang
  3 Lang:C++
  4 */
  5 #include <cstdio>
  6 #include <cstdlib>
  7 #include <sstream>
  8 #include <iostream>
  9 #include <cmath>
 10 #include <cstring>
 11 #include <algorithm>
 12 #include <string>
 13 #include <utility>
 14 #include <vector>
 15 #include <queue>
 16 #include <stack>
 17 #include <map>
 18 #include <set>
 19 using namespace std;
 20 
 21 typedef long long ll;
 22 #define DEBUG(x) cout<< #x << ':' << x << endl
 23 #define REP(i,n) for(int i=0;i < (n);i++)
 24 #define FOR(i,s,t) for(int i = (s);i <= (t);i++)
 25 #define FORD(i,s,t) for(int i = (s);i >= (t);i--)
 26 #define PII pair<int,int>
 27 #define PB push_back
 28 #define MP make_pair
 29 #define ft first
 30 #define sd second
 31 #define lowbit(x) (x&(-x))
 32 #define INF (1<<30)
 33 
 34 
 35 const int maxn = 5050;
 36 int pa[111],a[111];
 37 struct Edge
 38 {
 39     int u,v,w;
 40 }edge[maxn];
 41 
 42 bool cmp(Edge x,Edge y)
 43 {
 44     return x.w < y.w;
 45 }
 46 void init(int n)
 47 {
 48     FOR(i,1,n)pa[i] = i;
 49 }
 50 int findset(int x)
 51 {
 52     return x == pa[x] ? x : pa[x] = findset(pa[x]);
 53 }
 54 int kruskal(int n,int m,int key)
 55 {
 56     init(n);
 57     int ans = 0,cnt=0;
 58     REP(i,m)
 59     {
 60         if(i == key)continue;
 61         int x = findset(edge[i].u),y=findset(edge[i].v);
 62         if(x != y)
 63         {
 64             pa[x] = y;ans += edge[i].w;cnt++;
 65         }
 66         if(cnt == n-1)return ans;
 67     }
 68     return -INF;
 69 }
 70 int main()
 71 {
 72     //freopen("in","r",stdin);
 73     int T;
 74     scanf("%d",&T);
 75     while(T--)
 76     {
 77         int n,m;
 78         scanf("%d%d",&n,&m);
 79         REP(i,m)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
 80         sort(edge,edge+m,cmp);
 81         int ans = 0,cnt=0;
 82         init(n);
 83         REP(i,m)//最小生成树
 84         {
 85             int x = findset(edge[i].u),y=findset(edge[i].v);
 86             if(x != y)
 87             {
 88                 pa[x] = y;ans += edge[i].w;a[cnt++]=i;
 89             }
 90             if(cnt == n-1)break;
 91         }
 92         REP(i,n-1)
 93         {
 94             int tmp = kruskal(n,m,a[i]);
 95             if(ans == tmp)
 96             {
 97                 ans = -INF;break;
 98             }
 99         }
100         if(ans == -INF)puts("Not Unique!");
101         else printf("%d\n",ans);
102     }
103     return 0;
104 }
prim
 1 /*
 2 Author:Zhaofa Fang
 3 Lang:C++
 4 */
 5 #include <cstdio>
 6 #include <cstdlib>
 7 #include <sstream>
 8 #include <iostream>
 9 #include <cmath>
10 #include <cstring>
11 #include <algorithm>
12 #include <string>
13 #include <utility>
14 #include <vector>
15 #include <queue>
16 #include <stack>
17 #include <map>
18 #include <set>
19 using namespace std;
20 
21 typedef long long ll;
22 #define DEBUG(x) cout<< #x << ':' << x << endl
23 #define REP(i,n) for(int i=0;i < (n);i++)
24 #define FOR(i,s,t) for(int i = (s);i <= (t);i++)
25 #define FORD(i,s,t) for(int i = (s);i >= (t);i--)
26 #define PII pair<int,int>
27 #define PB push_back
28 #define MP make_pair
29 #define ft first
30 #define sd second
31 #define lowbit(x) (x&(-x))
32 #define INF (1<<30)
33 
34 
35 const int maxn = 5050;
36 int maz[maxn][maxn],path[maxn][maxn];
37 bool vist[maxn];
38 int dist[maxn],pre[maxn],Stack[maxn];
39 int n,m;
40 void init(void){
41     FOR(i,1,n)FOR(j,1,n)maz[i][j] = INF, path[i][j] = 0;
42 }
43 int prim(int s){
44     FOR(i,1,n)dist[i] = maz[s][i],vist[i] = 0,pre[i] = s;
45     int top =  0,sum = 0;
46     vist[s] = 1,dist[s] = 0, Stack[top++] = s;
47     while(1){
48         int u = -1;
49         FOR(i,1,n)
50             if(!vist[i] && (u == - 1 || dist[u] > dist[i]))
51                 u = i;
52         if(u == -1)break;
53         sum += dist[u],Stack[top++] =  u,vist[u] = 1;
54         REP(i,top){
55             if(Stack[i] == u)continue;
56             path[Stack[i]][u] = max(path[pre[u]][u],dist[u]);
57             path[u][Stack[i]] = path[Stack[i]][u];
58         }
59         FOR(i,1,n)
60             if(!vist[i] && (maz[u][i]<dist[i]))
61                 dist[i] = maz[u][i],pre[i] = u;
62     }
63     return sum;
64 }
65 void SMT(void){
66     int Min = INF,sum = prim(1);
67     FOR(i,1,n-1)
68         FOR(j,i+1,n)
69             if(pre[i] != j && pre[j] != i && maz[i][j] < INF)
70                 Min = min(Min, sum  - path[i][j] + maz[i][j]);
71     if(Min == sum)puts("Not Unique!");
72     else printf("%d\n",sum);
73 }
74 int main(){
75     //freopen("in","r",stdin);
76     int T;
77     scanf("%d",&T);
78     while(T--){
79         scanf("%d%d",&n,&m);
80         init();
81         int u,v,w;
82         while(m--)
83         {
84             scanf("%d%d%d",&u,&v,&w);
85             maz[u][v] = maz[v][u] = w;
86         }
87         SMT();
88     }
89     return 0;
90 }
原文地址:https://www.cnblogs.com/fzf123/p/2806346.html