判断最小生成树是否唯一
感觉这个做法特别暴力:先求出MST然后,枚举上面的边,逐个去掉后再跑kruskal,如果得到相等的结果,则不唯一
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node{
int x, y, dis;
int flag;
}a[10005];
int cmp(node x, node y){
return x. dis < y. dis;
}
int father[105], n;
int kruskal(int num, int m){
int ans = 0, cnt = 1;
for(int i = 0; i < m; i ++){
if(i == num)//除去这条边之后再求一次最小生成树
continue;
int s1 = father[a[i]. x];
int s2 = father[a[i]. y];
if(s1 != s2){
ans += a[i]. dis;
cnt ++;
father[s2] = s1;
for(int j = 0; j <= n; j ++)
if(father[j] == s2)
father[j] = s1;
}
}
if(cnt != n)
return -1;
else
return ans;
}
int main(){
int m, t, sum, ans, cnt;
scanf("%d", &t);
while(t --){
scanf("%d %d", &n, &m);
for(int i = 0; i <= n; i ++)
father[i] = i;
for(int i = 0; i < m; i ++){
scanf("%d %d %d", &a[i]. x, &a[i]. y, &a[i]. dis);
a[i].flag = 0;
}
sort(a, a + m, cmp);
cnt = 1;
ans = 0;
for(int i = 0; i < m; i ++){
int s1 = father[a[i]. x];
int s2 = father[a[i]. y];
if(s1 != s2){
a[i]. flag = 1;
ans += a[i]. dis;
cnt ++;
father[s2] = s1;
for(int j = 0; j <= n; j ++)
if(father[j] == s2)
father[j] = s1;
}
}
int flag = 0;
for(int i = 0; i < m; i ++){//枚举所有原最小生成树上的边
if(a[i]. flag == 0)
continue;
sum = 0;
for(int j = 0; j <= n; j ++)//初始化
father[j] = j;
sum = kruskal(i, m);
if(sum == ans){//与之前的最小生成树比较,如果相等,那么肯定不是唯一的
flag = 1;
break;
}
}
if(flag)
printf("Not Unique!\n");
else
printf("%d\n",ans);
}
return 0;
}
ps:附一个想法,以后再敲233
上面的做法不够优秀是因为它没有利用原图MST的结果。枚举每个点,将它和其余点连接,则会得到一个环,然后删掉这个环上另外的一条边,则得到的是最有可能成为MST的生成树,也就是说只要比较那两条边权值就可以了,相等,则不唯一