最小生成树(MST)—— Kruskal算法

Kruskal算法是一种贪心策略,用于构建最小生成树。它首先将边按权重升序排列,然后检查每条边是否连接不同连通块的顶点,如果是则加入最小生成树。该算法通过并查集维护连通块信息,直至找到(n-1)条边,形成一个连通的树结构。

Kruskal算法主要对边进行贪心,经过变换还可以求最大生成树,还可以记录树的具体路径。


Kruskal算法基本思想:


初始状态时隐去图中所有边,这样图中每个顶点都自成一个连通块。

  1. 对所有边权从小到大排序。
  2. 按边权从小到大测试所有边,如果当前测试边所连接的两个结点不在同一个连通块中,则把这条测试边加入最小生成树中( 合并两个连通块 );否则,将这条测试边舍弃
  3. 执行步骤2,直至最小生成树中的 边数等于 总结点数-1 或是 测试完所有边

概况一下就是:每次选择图中最小边权的边,如果边的两个端点在不同的连通块中,就把这条边加入最小生成树中。


伪代码

Kruskal()
{
	令最小生成树的边权之和为sum、最小生成树的当前边数为cnt;
	将所有边按边权从小到大排序;
	for(从小到大枚举所有边)
	{
		if(当前测试边的两个端点在不同的连通块中)
		{
			将该测试边加入最小生成树中;
			sum += 测试边边权;
			最小生成树的当前边数cnt加1;
			当边数cnt等于结点数减1时结束循环;
		}
	}
	return sum;
}

关于判断两结点是否处于同一连通块,可用并查集实现。



完整代码:(计算最小生成树的边权和)

struct edge
{
	int u, v;
	int w;
}E[maxm];    //存放边            
int N, M, father[maxn];       //N为结点数,M为边数
bool cmp(const edge &a, const edge &b)
{
	return a.w < b.w;
}
void init()                   //并查集的初始化
{
	for (int i = 0; i < maxn; i++)
		father[i] = i;
}
int findFather(int x)         //查找根
{
	int root = x;
	while (father[root] != root)
		root = father[root];
		
	//路径压缩
	while (father[x] != x)
	{
		int t = x;
		x = father[x];
		father[t] = root;
	}
	
	return root;
}
int Kruskal(int r)
{
	int sum = 0,cnt=0;
	sort(E,E+M,cmp);
	init();
	for (int i = 0; i < M; i++)
	{
		int Fu = findFather(E[i].u);
		int Fv = findFather(E[i].v);
		if (Fu != Fv)
		{
			father[Fv] = Fu;
			sum += E[i].w;
			cnt++:
			if(cnt==N-1)
				break;
		}
	}
	//注意:若cnt最终不等于N-1,说明存在无法连通的结点
	return sum;
}


PS. 摘自《算法笔记》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值