先来说明一下最小生成树不唯一的原因,大的方面来说就是存在权值相同的边,并且这些权值相同的边在构建MIT时都有可能被用到,这是解决这个问题的核心。其实这种情况开可以继续细分,
情况一:权值相同的顶点有公共顶点.
情况二;权值相同的点没有公共顶点
情况三:情况一 + 情况二
先来说一下kruslal算法的思想,
先构建图,统计图中是否存在权值相同的边,如果没有这种情况直接可判断出 MIT唯一。如果存在权值相同的边进行标记,然后进行构建MIT,将第一次构建的MIT,所有边进行标记(建立一个边集 E1),然后枚举集合E1中所有边,如果存在有权值相同的边的话,将这条边进行删除。在进行MIT,判断是否还可以构建出一颗权值相同的MIT,如果存在则可判断MIT不唯一。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 500 + 10;
struct Edge
{
int u,v,w;
bool used; // 为第一次建立MIT标记
bool deleted; // 删除标记
bool _equal; // 判断是否存在权值相同的边
};
Edge edge[MAXN * MAXN];
int father[MAXN];
int _rank[MAXN];
int first; //用来判断第一次建立MIT,建立边集E1
void init()
{
for(int i = 0; i <= MAXN - 1 ; ++i)
{
father[i] = i;
_rank[i] = 0;
}
return ;
}
int _find(int n)
{
int root = n;
int temp = n;
while(root != father[root])
{
root = father[root];
}
while(temp != root)
{
int t;
t = father[temp];
father[temp] = root;
temp = t;
}
return root;
}
void _union(int x,int y)
{
int root1 = _find(x),root2 = _find(y);
if(root1!= root2)
{
if(_rank[root1] > _rank[root2])
{
father[root2] = root1;
}
else
{
father[root1] = root2;
if(_rank[root1] == _rank[root2])
{
_rank[root2]++;
}
}
}
}
int m,n;
int kruskal()
{
init();
int sum = 0;
int ans = 0;
for(int i = 1;i <= m;++i)
{
if(edge[i].deleted)
continue;
int u,v;
u = edge[i].u;
v = edge[i].v;
if(_find(u) != _find(v))
{
ans += edge[i].w;
_union(u,v);
sum++;
if(first)
edge[i].used = 1;
}
if(sum == m - 1)
break;
}
return ans;
}
bool cmp(Edge a,Edge b)
{
return a.w < b.w;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--)
{
int w1 = 0,w2 = 0;
cin >> n >> m;
for(int i = 1; i <= m;++i)
{
cin >> edge[i].u >> edge[i].v >> edge[i].w;
edge[i].used = 0;edge[i].deleted = 0;edge[i]._equal = 0; // 初始化边的信息
}
for(int i = 1; i<= m;++i)
{
for(int j = 1;j <= m;++j)
{
if(i != j && edge[i].w == edge[j].w)
{
edge[j]._equal = 1; // 寻找是否存在相同的边
}
}
}
sort(edge + 1,edge + m + 1,cmp);
first = 1;
w1 = kruskal();
first = 0;
int flag = 0;
for(int i = 1; i <= m; ++i) //枚举E1中的边
{
if(edge[i].used && edge[i]._equal)
{
edge[i].deleted = 1; // 删除已经发现的边
w2 = kruskal();
if(w1 == w2)
{
flag = 1;
cout << "Not Unique!" << endl;
break;
}
edge[i].deleted = 0;
}
}
if(!flag)
{
cout << w1 << endl;
}
}
return 0;
}