C++图论提高——The Unique MST (最小生成树 Kruskal算法)

题目描述(传送门

给定连接的无向图,告诉它的最小生成树是否唯一。 

定义1(生成树):考虑连通的无向图G =(V,E)。G的生成树是G的子图,比如T =(V',E'),具有以下属性: 
1.V'= V. 
2.T是连通的和非循环的。 

定义2(最小生成树):考虑边加权,连通,无向图G =(V,E)。G的最小生成树T =(V,E')是总成本最小的生成树。T的总成本是指E'中所有边缘的权重之和。 

输入

第一行包含单个整数t(1 <= t <= 20),即测试用例的数量。每个案例代表一个图表。它以包含两个整数n和m(1 <= n <= 100),节点数和边数的行开始。以下m行中的每一行包含三元组(xi,yi,wi),表示xi和yi通过权重= wi的边连接。对于任何两个节点,最多只有一个边连接它们。

产量

对于每个输入,如果MST是唯一的,则打印它的总成本,否则打印字符串'Not Unique!'。

样本输入

2
3 3
1 2 1
2 3 2
3 1 3
4 4
1 2 2
2 3 2
3 4 2
4 1 2

2 3 2
3 4 2
4 1 2

样本输出

3
 Not Unique!


分析

拿到这道题的第一反应是,这TM什么鬼,鬼知道你是不是唯一的啊!!!

但静下心仔细想想,就能想到拿最小生成树MST和次小生成树MST比较一下就知道了,如果相等,说明其不唯一。反之,唯一。

那对于此题该如何做呢,很快就会想到Kruskal算法,先把边从小到大排序,再一条一条边地插入再用并查集构成最小生成树,

那又该怎样求次小生成树呢 ?

只需要将最小生成树的边破坏一条,再求一次最小生成树就可以了。

如果不懂结合代码理解理解


代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int t , n , m  , f[101] ;// f 用来记录父亲节点

struct node{
	int f , t , w ;
    // f 表示起点, t 表示终点, w 表示权值
};

node e[10001] ;//图的边

int add[101] ;//记录最小生成树的边

bool cmp( node x , node y )
{
	return x.w < y.w;
}

int findf(int x)
{
	while( x != f[x]) x = f[x] = f[f[x]];//查找父亲节点
	return x;
}

bool Un(int x , int y)
{
	int fx , fy ;
	fx = findf(x);
	fy = findf(y);
	if( fy != fx )//如果父亲节点不相等,则连接父亲节点
	{
		f[fy] = fx ;
		return 1 ;//表示连接了两条边
	}
	return 0 ;
}

int K( int x )//表示破坏的边
{
	int MST = 0 , cnt = 0 ;
	for(int i = 1 ; i <= n ; ++ i )//重置父亲节点
		f[i] = i ;
	for(int i = 1 ; i <= m ; ++ i )//枚举边
	{
		if(i == x) continue;
		if( Un( e[i].f , e[i].t ) )//如果两点连接
		{
			MST += e[i].w ;
			cnt ++ ;
			if(x==0) add[cnt] = i;//记录最小生成树的边
		}
		if( cnt == n - 1 )
			return MST;
	}
	return -1 ;
}

int main()
{
	scanf("%d", &t );
	for(int k = 1 ; k <= t ; ++ k )
	{
		memset( f , 0 , sizeof(f) );
		scanf("%d%d", &n , &m );
		if( n == 1 && m == 0 )
		{
			cout<< 0 <<endl ;
			continue;
		} 
		for(int i = 1 ; i <= m ; ++ i )
		{
			scanf("%d%d%d", &e[i].f , &e[i].t , &e[i].w );
		}
		sort( e + 1 , e + m + 1 , cmp );//对边进行排序
		int MST = K(0);//求出最小生成树的MST
		bool flag = 0;
		for(int i = 1 ; i < n  ; ++ i )
			if(!flag && K(add[i])==MST) {
				puts("Not Unique!");
				flag = 1;
			}
		if(!flag) printf("%d\n",MST);
	}
}

对于图论,本人也是初学者,写这篇博客时也颇有感触

猜你喜欢

转载自blog.csdn.net/qq_44013342/article/details/86694767