模板 次小生成树
Posted xiaobuxie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板 次小生成树相关的知识,希望对你有一定的参考价值。
1 /*for(遍历图中所有不属于最小生成树的边) 2 把当前边加入最小生成树产生回路 3 去掉回路中除当前边之外权值最大的边 4 记录下现在的树及其总权值 5 在上面循环产生的树中选一棵总权值最小的,就是次小生成树*/ 6 /*上面做法只遍历一次最小生成树,但是如果枚举删去最小生成树上的边,那就要求n-2次最小生成树了,所以不可取*/ 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 #include<queue> 11 using namespace std; 12 typedef pair<int,int> pii; 13 const int maxn = 111; 14 const int inf = 0x3f3f3f3f; 15 int g[maxn][maxn];//邻接矩阵存图 16 int Max[maxn][maxn];//表示最小生成树中i到j的最大边权 17 bool used[maxn][maxn];//判断该边是否加入最小生成树 18 int pre[maxn];//点在最小生成树上的前驱 19 int dis[maxn];//在已存的点集中,到各个点的最短边 20 bool vis[maxn];//判断该点是否加入最小生成树 21 int T,n,m; 22 int prim() 23 24 int sum= 0; 25 memset(vis, false, sizeof(vis)); 26 memset(used, false, sizeof(used)); 27 memset(Max, 0, sizeof(Max)); 28 memset(dis,0x3f3f3f3f,sizeof(dis)); 29 dis[1]=0; 30 pre[1]=0; 31 priority_queue<pii,vector<pii>,greater<pii> >q; 32 q.push(make_pair(0,1)); 33 int all=0; 34 while(!q.empty()) 35 int u=q.top().second; 36 q.pop(); 37 if(vis[u]) continue; 38 vis[u]=1; 39 //就是只有当我确定了u这个点进入了最小生成树,我才改used数组和Max,之间都只是根据dis修改pre; 40 used[u][pre[u]]=used[pre[u]][u]=1; 41 ++all; 42 sum+=dis[u]; 43 for(int j=1;j<=n;++j) 44 if(vis[j]) 45 if(j!=u) Max[j][u]=Max[u][j]=max(Max[j][pre[u]],dis[u]); 46 else Max[j][u]=0; 47 //相当于一个dp,求出j到u之间最长边的边权. 48 49 else if(g[j][u]!=0x3f3f3f3f&&dis[j]>g[j][u]) 50 dis[j]=g[j][u]; 51 pre[j]=u; 52 q.push(make_pair(dis[j],j)); 53 54 55 56 if(all<n) return -1; 57 return sum;//最小生成树的权值之和 58 59 int smst(int sum)//sum是最小生成树的权值和 60 61 int ans=0x3f3f3f3f; 62 for (int i = 1; i <= n; i++)//枚举最小生成树之外的边 63 for (int j = i + 1; j <= n; j++) 64 if (g[i][j]!=0x3f3f3f3f&&!used[i][j]) 65 //加一条连接i和j(保证之后可以构成生成树)的且不在最小生成树的边,再删去i和j中最大边权的边 66 ans=min(ans,sum+g[i][j]-Max[i][j]); 67 if (ans==0x3f3f3f3f) return -1; 68 return ans; 69 70 int main() 71 72 scanf("%d", &T); 73 while (T--) 74 75 scanf("%d %d", &n, &m); 76 memset(g,0x3f3f3f3f,sizeof(g)); 77 for(int i=1;i<=n;++i) g[i][i]=0; 78 int u,v,w; 79 for(int i=1;i<=m;++i) 80 scanf("%d%d%d",&u,&v,&w); 81 g[u][v]=g[v][u]=min(g[u][v],w); 82 83 int ans=prim(); 84 if(ans==-1) puts("Not Unique!"); 85 else if(smst(ans)==ans) puts("Not Unique!"); 86 else printf("%d\n",ans); 87 //题目要判断最小生成树是否唯一 88 89 return 0; 90
以上是关于模板 次小生成树的主要内容,如果未能解决你的问题,请参考以下文章
Luogu P4180 模板严格次小生成树[BJWC2010]