判断MST(最小生成树)是否唯一的算法:
下面给大家介绍用Kruscal的简单变形就可以解决本题,时间复杂度为O(M+MlogM),包括了快排的时间复杂度,0MS。
注意到Kruscal贪心每次找出边权最小的边判断能否合并,假设找到了一条边权最小的边,其两个顶点所在集合的根节点分别为x和y,
向后搜寻边权与当前边相同的边(即当前边权最小的边不唯一),若搜寻到的边两个顶点的根节点同样是x和y,则这两个集合合并就有了两种方法,
此时就可以直接输出NotUnique!并退出。这样除了qsort以外的时间复杂度就被控制在O(m)以内。
#include <iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<queue> #include<stack> using namespace std; #define maxm 20000 #define maxn 150 struct list { int u,v,w; friend bool operator < (const list &a,const list &b) { return a.w<b.w; } } edge[maxm],p,q; int vis[maxm]; int f[maxn]; int find(int x) { while(x!=f[x])x=f[x]; return x; } int vp[maxm]; int maps[maxn][maxn]; int pan(int a,int b,int c,int d) { if(a==c&&b==d)return 1; if(a==d&&b==c)return 1; return 0; } int main() { int T,n,m,i; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(maps,0,sizeof(maps)); for(i=1; i<=n; i++)f[i]=i; for(i=1; i<=m; i++)scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge+1,edge+m+1); memset(vis,0,sizeof(vis)); for(i=2; i<=m; i++) { if(edge[i].w==edge[i-1].w)vis[i]=vis[i-1]=1; } int ans=0; int leap=0; int j; queue<list>que; while(!que.empty())que.pop(); for(i=1; i<=m; i++) { int a=find(edge[i].u); int b=find(edge[i].v); if(a==b)continue; p.u=a; p.v=b; que.push(p); for(j=i+1;j<=m;j++) { if(edge[j].w==edge[i].w) { int aa=find(edge[j].u); int bb=find(edge[j].v); if(aa==bb)continue; p.u=a; p.v=b; que.push(p); } else break; } i=j-1; while(!que.empty()) { p=que.front(); que.pop(); a=p.u; b=p.v; if(f[a]==b||f[b]==a) { leap=1; break; } f[a]=b; } if(leap==1)break; ans+=edge[i].w; f[a]=b; } if(leap)cout<<"Not Unique!"<<endl; else cout<<ans<<endl; } return 0; }