题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1541
题意:求一个图的最小生成树和次小生成树。
题解:
/*
*算法引入:
*设G=(V,E,w)是连通的无向图,T是图G的一棵最小生成树;
*如果有另一棵树T1,满足不存在树T’,ω(T’)<ω(T1),则称T1是图G的次小生成树;
*
*算法思想:
*邻集的概念:由T进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T);
*设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T’)|T’∈N(T)},则T1是G的次小生成树;
*首先先求该图的最小生成树T,时间复杂度O(Vlog2V+E);
*然后,求T的邻集中权值和最小的生成树,即图G 的次小生成树;
*如果只是简单的枚举,复杂度很高;
*首先枚举两条边的复杂度是O(VE),再判断该交换是否可行的复杂度是O(V),则总的时间复杂度是O(V2E);
*分析可知,每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树;
*而删去边的权值越大,新得到的生成树的权值和越小,可以以此将复杂度降为O(VE);
*更好的方法:首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边;
*然后枚举图中不在树上的边,有了预处理,就可以用O(1)的时间得到形成的环上的权值最大的边;
*预处理:因为是一棵树,只要简单的BFS即可,预处理所要的时间复杂度为O(V2);
* /
引用自:http://blog.csdn.net/jarily/article/details/8883858
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int VMAX=100+5; const int EMAX=VMAX*VMAX; const int INF=0x3f3f3f3f; int g[VMAX][VMAX],maxd[VMAX][VMAX];//g---存图,maxd存树上两点之间路径的最大权 int vis[VMAX]; int dist[VMAX]; int pre[VMAX];//前驱 int use[VMAX][VMAX];//0表示没用过,1表示用过,2表示不存在 int n,m; int firmst,secmst; int prim() { memset(maxd,0,sizeof(maxd)); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { dist[i]=g[1][i]; pre[i]=1; } firmst=0; vis[1]=1; for(int i=1;i<n;i++) { int p=-1,mmin=INF; for(int j=1;j<=n;j++) { if(!vis[j]&&mmin>dist[j]) { mmin=dist[j]; p=j; } } if(p!=-1) { use[pre[p]][p]=use[p][pre[p]]=1; for(int j=1;j<=n;j++) { if(vis[j]) { maxd[j][p]=max(maxd[j][pre[p]],g[pre[p]][p]); } } vis[p]=1; firmst+=mmin; for(int j=1;j<=n;j++) { if(!vis[j]&&dist[j]>g[p][j]) { dist[j]=g[p][j]; pre[j]=p; } } } } return firmst; } int secMst() { int mmin=INF; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(use[i][j]==0) mmin=min(mmin,g[i][j]-maxd[i][j]); } } return secmst=firmst+mmin; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { g[i][j]=INF; use[i][j]=2; } } while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); g[a][b]=c; g[b][a]=c; use[a][b]=0; use[b][a]=0; } prim(); secMst(); printf("%d %d\n",firmst,secmst); } return 0; }