判断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;
}