【POJ1697】次小生成树

题目链接:http://poj.org/problem?id=1679

题目大意:让你求最小生成树,并判断最小生成树是否唯一。

解题思路:本题其实是想让你求次小生成树,如果次小生成树和最小生成树权值和相等,最小生成树则不唯一,否则唯一。

解题步骤:

1、先求最小生成树,求最小生成树过程中标记出现在最小生成树中的边以及fp[i][j],fp数组保存的是最小生成树上从i到j的最大权值。

2、枚举所有未出现在最小生成树中的边map[i][j],找到tp=(map[i][j]-fp[i][j])差值最小的进行替换,为什么可以这样?因为加入map[i][j]到最小生成树中后必形成环,然后消去环中非map[i][j]的最大权值边,得到的解必为最优解。

3、tp==0则最小生成树不唯一,否则唯一。

View Code
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <queue>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 const int maxn=110;
10 const int oo=0x3fffffff;
11 int lowcost[maxn], visit[maxn], map[maxn][maxn], used[maxn][maxn], pre[maxn], fp[maxn][maxn]; ///fp数组保存的是最小生成树上从i到j的最大权值边
12 int n, m, T;
13 
14 int Prim()
15 {
16     int sum=0;
17     for(int i=1; i<=n; i++) lowcost[i]=oo, pre[i]=0, visit[i]=0;
18     lowcost[1]=0;
19     for(int i=1; i<=n; i++)
20     {
21         int k=-1, minn=oo;
22         for(int j=1; j<=n; j++)
23             if(minn>lowcost[j]&&!visit[j]) k=j, minn=lowcost[j];
24         if(k==-1) break;
25         if(pre[k]!=0)     ///源点不考虑进去
26         {
27             used[pre[k]][k]=used[k][pre[k]]=2; ///出现在最小生成树中的边标记一下
28             for(int j=1; j<=n; j++)
29                 if(visit[j]) fp[j][k]=max(fp[j][pre[k]],map[pre[k]][k]); ///找生成树中已出现的节点j,求j到k路上最大权值边
30         }
31         visit[k]=1;
32         sum+=lowcost[k];
33         lowcost[k]=0;
34         for(int j=1; j<=n; j++)
35             if(!visit[j]&&lowcost[j]>map[k][j])
36             {
37                 pre[j]=k;
38                 lowcost[j]= map[k][j];
39             }
40     }
41     return sum;
42 }
43 
44 void Solve()
45 {
46     int ans=Prim();
47     int tp=oo;
48     for(int i=1; i<=n; i++)
49         for(int j=1; j<=n; j++)
50            if(used[i][j]==1) tp=min(tp,map[i][j]-fp[i][j]); ///枚举未出现在生成树中的边
51     if(tp==0) puts("Not Unique!");
52     else printf("%d\n",ans);
53 }
54 
55 int main()
56 {
57     cin >> T;
58     while(T--)
59     {
60         scanf("%d%d",&n,&m);
61         for(int i=1; i<=n; i++)
62             for(int j=1; j<=n; j++) fp[i][j]=used[i][j]=0, map[i][j]=oo;
63         for(int i=0; i<m; i++)
64         {
65             int u, v, val;
66             scanf("%d%d%d",&u,&v,&val);
67             map[u][v]=map[v][u]=val;
68             used[u][v]=used[v][u]=1;
69         }
70         Solve();
71     }
72     return 0;
73 }
原文地址:https://www.cnblogs.com/kane0526/p/3056399.html