次小生成树

求给定图的次小生成树。

对于给定的图,我们可以证明,次小生成树可以由最小生成树变换一边得到。那么我们可以如下求给定图的次小生成树。首先,我们用prime算法求出图的最小生成树,在这个过程中记录每条边是否用过,以及两个点之间最短路径上的最大权值F[i,j]

 

F[i,j]可以如此求得,当加入点u的时候,并且u的父结点是v 那么对于已经在生成树中的节点x

F[x,u] = max(F[x,v], weight[u][v]),那么我么就可以用Prime算法一样的时间复杂度来求出图的次小生成树。如下是我的代码,通过了uva 10600:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=18&problem=1541&mosmsg=Submission+received+with+ID+7266392

#include "iostream" #include "cstdio" #include "cstring" #define EXIST 1 #define NOT_EXIST 0 #define USE 2 using namespace std; const int MaxN = 110; const int Inf = 0x7fffffff; int g[MaxN][MaxN]; int N,M; char use[MaxN][MaxN]; int ans1,ans2,F[MaxN][MaxN]; int prime(){ int dis[MaxN]; bool vis[MaxN]; int pre[MaxN]; memset(pre,0xff,sizeof(pre)); memset(vis,false,sizeof(vis)); for(int i = 0 ;i < MaxN; ++i) dis[i] = Inf; dis[1] = 0; for(int i = 1; i <= N; ++i){ int pos; int tmp = Inf; for(int j = 1;j <= N; ++j){ if(!vis[j] && dis[j] < tmp){ tmp = dis[j]; pos = j; } } if(pre[pos] != -1){ use[pre[pos]][pos] = use[pos][pre[pos]] = USE; for(int j = 1;j <= N; ++j){ if(vis[j]) F[j][pos] = max(F[j][pre[pos]],g[pre[pos]][pos]); } } vis[pos] = true; ans1 += dis[pos]; for(int j = 1;j <= N; ++j){ if(!vis[j] && g[pos][j]!= 0 && g[pos][j] < dis[j]){ dis[j] = g[pos][j]; pre[j] = pos; } } } return ans1; } int Second_MST(){ ans2 = Inf; for(int i = 1;i <= N; ++i){ for(int j = 1;j <= N; ++j){ if(use[i][j] == EXIST){ if(ans1 + g[i][j] - F[i][j] < ans2) ans2 = ans1 + g[i][j] - F[i][j]; } } } return ans2; } int main(){ int T; scanf("%d",&T); while(T--){ memset(g,0,sizeof(g)); memset(use,0,sizeof(use)); memset(F,0,sizeof(F)); ans1 = ans2 = 0; scanf("%d%d",&N,&M); for(int i = 0 ;i < M; ++i){ int A,B,C; scanf("%d%d%d",&A,&B,&C); g[A][B] = g[B][A] = C; use[A][B] = use[B][A] = EXIST; } printf("%d ",prime()); printf("%d/n",Second_MST()); } return 0; }  

在代码中用use[i][j] 表示边i,j是否用过,1表示存在,但没有用过,0表示不存在,2表示存在,并且已经在最小生成树中。

你可能感兴趣的:(c,算法,iostream)