The Unique MST——最小生成树(判断最小生成树的唯一性)
题意:
给一个图,问其最小生成树是否唯一。
题解:
用Kruskal 算出最小生成树的值,并记录每一条边,然后枚举去掉这些边 看其是否也能构成最小生成树且值相同。
注意 在删边后,可能图构不成一棵树,得判断一下。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<stdio.h> #include<math.h> #include<algorithm> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn = 10005; int f[maxn]; int n,cnt,m; int vis[maxn]; struct node { int u,v; int w; bool operator < (const node &a)const { return w<a.w; } } edge[maxn]; int Find(int x) { return x==f[x]?x:f[x]=Find(f[x]); } void add(int u,int v,int w) { edge[cnt].u=u; edge[cnt].v=v; edge[cnt++].w=w; } void kruskal() { int ans=0; int cntt=0; int flag=1; for(int i=0; i<=n; i++)f[i]=i; sort(edge,edge+cnt); for(int i=0; i<cnt; i++) { int x=edge[i].u; int y=edge[i].v; int fx=Find(x); int fy=Find(y); if(fx!=fy) { f[fx]=fy; vis[cntt++]=i; ans+=edge[i].w; } } for(int i=0;i<cntt;i++) { for(int k=0; k<=n; k++)f[k]=k; int sum=0,res=0; for(int j=0;j<cnt;j++) { if(j==vis[i])continue; int x=edge[j].u; int y=edge[j].v; int fx=Find(x); int fy=Find(y); if(fx!=fy) { f[fx]=fy; res+=edge[j].w; sum++; } } if(ans==res && sum==n-1){flag=0;break;}///判断是否能构成树 且 是否与最小生成树相等 } if(flag)printf("%d\n",ans); else printf("Not Unique!\n"); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); cnt=0; for(int i=1; i<=m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } kruskal(); } return 0; }
也可以套用次小生成树的模板
判断最小生成树和次小生成树是否相等 相等就输出 Not Unique! 否则输出最小生成树的值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <vector> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; int n,m; struct node { int u,v,w; bool vis; bool operator < (const node &a) { return w<a.w; } } p[20010]; vector<int>G[110]; int per[110],maxd[110][110]; int Find(int x) { return x == per[x] ? x: per[x] = Find(per[x]); } void kruskal() { sort(p,p+m); for(int i=0; i<=n; i++)//初始化 { G[i].clear(); G[i].push_back(i); per[i]=i; } int sum=0,k=0;//sum是最小生成树的值 for(int i=0; i<m; i++) { if(k==n-1) break; int x1=Find(p[i].u),x2=Find(p[i].v); if(x1!=x2) { k++; p[i].vis=1; sum+=p[i].w; int len_x1=G[x1].size(); int len_x2=G[x2].size(); for(int j=0; j<len_x1; j++) for(int k=0; k<len_x2; k++) maxd[G[x1][j]][G[x2][k]]=maxd[G[x2][k]][G[x1][j]]=p[i].w; per[x1]=x2; for(int j=0; j<len_x1; j++) G[x2].push_back(G[x1][j]); } } int cisum=INF;//次小生成树的权值 for(int i=0; i<m; i++) if(!p[i].vis) cisum=min(cisum,sum+p[i].w-maxd[p[i].u][p[i].v]); if(sum==cisum)printf("Not Unique!\n"); else printf("%d\n",sum); } int main() { int T; scanf("%d\n",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0; i<m; i++) { scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w); p[i].vis = false; } kruskal(); } return 0; }