次小生成树
我们大部分都对最小生成树了解的多一些,一般求最小生成树的算法是prim、kurskal,那么对于次小生成树,我们也可以用上面两种算法来求解
算法解释
这两种算法的思路都是相同的,首先求出最小生成树,我们枚举每条不在最小生成树上的边,并把这条边放到最小生成树上面,然后就一定会形成环,那么我们在这条环路中取出一条最长的路(除了新加入的那一条边)。最终我们得到的权值就是次小生成树的权值。
这里我采用的是kruscal求次小生成树
不妨开一个二维数组maxd[u][v] 代表从 u 到 v的最小距离,因为kruscal求最小生成树的时候就是从最短的距离开始枚举的嘛,所以一开始枚举的肯定是最小的!
之后我们如何去求次小生成树呢?
首先假设ans代表最小生成树的值,并且我们把这个最小生成树的所有边都标记。然后我们去枚举未被标记的边(从小开始枚举),找到一个就进行替换
1 cisum = std::min(cisum,ans+e[i].w-maxd[e[i].u][e[i].v]);
板子题:The Unique MST
题目连接:https://vjudge.net/problem/POJ-1679
直接上板子吧
1 #include <math.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <string.h> 8 #include <vector> 9 #include <map> 10 #include <stack> 11 #include <set> 12 #include <queue> 13 14 15 #define LL long long 16 #define INF 0x3f3f3f3f 17 #define ls nod<<1 18 #define rs (nod<<1)+1 19 const int maxn = 2e4+10; 20 const double eps = 1e-9; 21 std::vector<int> G[110]; 22 int maxd[110][110]; 23 24 int n,m,ans,cnt,cisum,fa[5050]; 25 26 struct node{ 27 int u, v, w; 28 bool vis; 29 }e[maxn]; 30 31 bool cmp(node a, node b) 32 { 33 return a.w < b.w; 34 } 35 36 int fid(int x) 37 { 38 return x == fa[x] ? x : fid(fa[x]); 39 } 40 41 void init(int n) 42 { 43 for(int i = 1; i <= n; i++) { 44 G[i].clear(); 45 G[i].push_back(i); 46 fa[i] = i; 47 } 48 ans = 0; 49 cnt = 0; 50 } 51 52 void kruskal() 53 { 54 std::sort(e+1, e+m+1, cmp); 55 for(int i = 1; i <= m; i++) { 56 int eu = fid(e[i].u); 57 int ev = fid(e[i].v); 58 if(eu == ev) { 59 continue; 60 } 61 ans += e[i].w; 62 e[i].vis = true; 63 int len_eu = G[eu].size(); 64 int len_ev = G[ev].size(); 65 for (int j=0;j<len_eu;j++) { 66 for (int k=0;k<len_ev;k++) { 67 maxd[G[eu][j]][G[ev][k]] = maxd[G[ev][k]][G[eu][j]] = e[i].w; 68 } 69 } 70 fa[ev] = eu; 71 for (int j=0;j<len_ev;j++) { 72 G[eu].push_back(G[ev][j]); 73 } 74 if(++cnt == n-1) { 75 break; 76 } 77 } 78 cisum = INF; 79 for (int i=1;i<=m;i++) { 80 if (!e[i].vis) { 81 cisum = std::min(cisum,ans+e[i].w-maxd[e[i].u][e[i].v]); 82 } 83 } 84 } 85 86 int main() { 87 int T; 88 scanf("%d",&T); 89 while (T--) { 90 scanf("%d%d",&n,&m); 91 for (int i=1;i<=m;i++) { 92 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 93 e[i].vis = false; 94 } 95 init(n); 96 kruskal(); 97 if (cisum>ans) 98 printf("%d\n",ans); 99 else 100 printf("Not Unique!\n"); 101 } 102 return 0; 103 }