次小生成树,顾名思义,求最小生成树之外的最小生成树,即倒数第二小的生成树。
先利用prim求出最小生成树。并将最小生成树任意两点之间路径当中的权值最大的那一条找出来,为什么要找最大的呢,因为生成树再加入一条边之后一定构成了回路,那么肯定要去掉这个回路当中一条边才是生成树,那么,怎么去边才是次小的,那就去掉除了刚刚添加的一条边之外回路当中权值最大的一个,所以留下的就是最小的。
题目:POJ1679
题意:给定图,让求它的最小生成树是否唯一。如果唯一的话输出最小生成树的权值和,否则输出Not Unique!
#include <iostream> #include <stdio.h> #define MAX 0x3f3f3f3f const int N = 105; using namespace std; int mp[N][N],vis[N],dis[N],st[N],max1[N][N],pre[N]; int n,m,ans; void Init(){ for(int i = 0;i < N; i++) for(int j = 0; j < N; j++){ mp[i][j] = mp[j][i] = MAX; max1[i][j] = max1[j][i] = 0; } fill(vis,vis+N,0); } void prim(){ int min_value,top = 0,k; vis[1] = 1; ans = 0; for(int i = 1;i <= n; i++) { pre[i] = 1; dis[i] = mp[1][i]; } dis[1] = 0; st[top++] = 1;//保存MST的结点 for(int i = 1;i <= n; i++){ min_value = MAX; for(int j = 1; j <= n; j++){ if(!vis[j]&&min_value>dis[j]) min_value = dis[k = j]; } if(min_value==MAX) break; vis[k] = 1; ans += min_value; for(int j = 0;j < top; j++) max1[st[j]][k] = max1[k][st[j]] = max(min_value,max1[st[j]][pre[k]]);//新加入点到MST各点路径最大值 st[top++] = k;//保存MST的结点 for(int j = 1;j<=n;j++) if(!vis[j]&&dis[j]>mp[k][j]) { dis[j] = mp[k][j]; pre[j] = k;//记录直接前驱 } } } int main() { int t; cin>>t; while(t--){ Init(); int s,e,value; cin>>n>>m; for(int i = 0;i < m;i++) { cin>>s>>e>>value; mp[s][e] = mp[e][s] = value; } prim(); int minn = MAX; for(int i = 1; i <= n; i++)枚举MST以外的边 for(int j = 1;j <= n; j++) if(i!=j&&i!=pre[j]&&j!=pre[i]) minn = min(minn,mp[i][j]-max1[i][j]); if(minn) cout<< ans <<endl; else cout<< "Not Unique!"<<endl; } return 0; }