题意:给定一个连通的无向图,判断最小生成树是否唯一。
思路:
1.对于图中每条边,把存在相同权值的边作一个标记。
2.然后求出MST。
3.求的MST后如果该MST未包含标记的边,则可判定MST唯一;如果包含了作了标记的边,则一次去掉这些边再求MST,如果求得的MST和原来的MST权值相同,即可判定MST不唯一。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 105;
const int maxm = 5005;
struct edge{
int u,v;
int w;
bool equal;//是否存在相等的边
bool used;//第一次构造时是否使用
bool del;//是否删除
bool operator < (const edge &b) const{
return w < b.w;
}
};
int n,m;
edge a[maxm];
int p[maxn];
bool fg; //是否是第一次构造
void UFset(){
for(int i = 0; i <= n; i++)
p[i] = -1;
}
int Find(int x){
return p[x] >= 0 ? p[x] = Find(p[x]) : x;
}
void Union(int r1, int r2){
r1 = Find(r1);
r2 = Find(r2);
int t = p[r1] + p[r2];
if(p[r1] > p[r2]){
p[r1] = r2;
p[r2] = t;
}
else{
p[r2] = r1;
p[r1] = t;
}
}
int Kruskal(){
int sum = 0;
int num = 0;
UFset();
for(int i = 0; i < m; i++){
if(a[i].del)//这条边已经被去除
continue;
int u = a[i].u, v = a[i].v;
if(Find(u) != Find(v)){
Union(u,v);
sum += a[i].w;
num++;
if(fg) a[i].used = true;
}
if(num >= n-1)
break;
}
return sum;
}
int main(){
int t;
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
cin>>t;
while(t--){
cin>>n>>m;
for(int i = 0; i < m; i++){
cin>>a[i].u>>a[i].v>>a[i].w;
a[i].del = false;
a[i].equal = false;
a[i].used = false;
}
sort(a,a+m);
for(int i = 1; i < m; i++){//标记权值相等的边
if(a[i].w == a[i-1].w){
a[i].equal = true;
a[i-1].equal = true;
}
}
fg = true;
int w1 = Kruskal();
int w2 = -1;
fg = false;
for(int i = 0; i < m; i++){
if(a[i].used && a[i].equal){
a[i].del = true;
w2 = Kruskal();
if(w1 == w2){
cout<<"Not Unique!\n";
break;
}
a[i].del = false;
}
}
if(w1 != w2)
cout<<w1<<"\n";
}
return 0;
}