次小生成树POJ 1679

本文介绍了如何通过Kruskal算法判断一个无向图是否存在次小生成树,并提供了详细的实现思路及源代码。通过判断是否有相同权重的边连接相同的两个树根节点来确定次小生成树的存在性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ的题目地址:http://poj.org/problem?id=1679

次小生成树是给定一个无向图,让我们计算得出这个无向图的最小生成树是否是唯一的。对于一个无向图的最小生成树,我们知道,它是连通的,而且每一条边都为割边。所以,当我们拿去一条边L的时候,树就会分裂成两个联通分支。这时,我们加入一条异于L的边L1,令两个联通分支重新形成一棵树。如果L1的长度和L的长度相等。那么我们就可以得到两棵最小生成树。此时即存在次小生成树。

在这里,我们利用kruskal算法,在kruskal算法中,每一次加入一条边,即将两个联通分支联通起来。而每个联通分支即可视为一棵小树。而小树存在一个树根。如果在加入一条边的之后能够找到同样长度的一条边,让两个联通分支连接起来(即这条边的两个节点可以回溯到同样的两个树根),那么我们就可以知道这棵树存在次小生成树。问题就得到了解决。

同样的,用于求最小生成树的PRIM算法也可以用来求次小生成树。

下面附上题目的源代码:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct road
{
	int a, b, v;
}data[25100];
int father[105], dev[105],n,m,t;
bool comp(road a, road b)
{
	if (a.v < b.v)return true;
	else return false;
}
void init()
{
	int i;
	for (i = 1; i <= n; i++)
	{
		father[i] = i;
		dev[i] = 0;
	}
}
int findroot(int a)
{
	if (a != father[a])
		father[a] = findroot(father[a]);
	return father[a];
}
void union_set(int a, int b)
{
	if (father[a] == father[b])return;
	else if (dev[a] >= dev[b])
	{
		dev[a]++;
		father[b] = a;
	}
	else
	{
		dev[b]++;
		father[a] = b;
	}
}
int kruskal()
{
	int sum=0, flag = 0,i,x,y,j;
	sort(data + 1, data + m+1, comp);
	for (i = 1; i <= m; i++)
	{
		if (findroot(data[i].a) == findroot(data[i].b))continue;
		else
		{
			x = findroot(data[i].a); y = findroot(data[i].b);
			for (j = i + 1; j <= m;j++)
			{
				if (data[j].v != data[i].v)break;
				else if (findroot(data[j].a) == x&&findroot(data[j].b) == y)
				{
					flag = 1;
					break;
				}
			}
		}
		if (flag)break;
		union_set(data[i].a, data[i].b);
		sum += data[i].v;
	}
	if (flag)return -1;
	else return sum;
}
int main()
{
	int i, a,b,ans;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		init();
		for (i = 1; i <= m; i++)
		{
			cin >> a >> b >> data[i].v;
			data[i].a = min(a, b);
			data[i].b = max(a, b);
		}
		ans = kruskal();
		if (ans < 0)cout << "Not Unique!" << endl;
		else cout << ans << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值