最小生成树——Kruskal算法

本文介绍了Kruskal算法用于求解最小生成树的问题,详细阐述了算法思路,即按边权值排序后,使用并查集判断边是否形成环并进行集合合并。Kruskal算法时间复杂度为O(E*logE),确保找到最小生成树。文中还包含了算法的伪代码和并查集优化策略的解释。

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

引例

有一张城市地图,图中顶点为城市,无向边代表两个城市间的连通关系,边上的权为在这两个城市间修建高速公路的造价,研究后发现,这个地图有一个特点,即每一对城市都是连通的。现在的问题是,要修建若干高速公路把所有城市联系起来,问如何设计可使的工程的总造价最少?
在这里插入图片描述
考虑问题的出发点是:为使生成树上边的权值和最小,则应使生成树中每一条边的权值尽可能的小。

进入正题
  • Kruskal算法是一种巧妙地利用并查集来求最小生成树的算法
  • Kruskal算法将一个连通块当做一个集合。首先将所有边按从小到大的顺序排序(一般使用快排),并认为每一个顶点都是孤立的,分别属于n个独立的集合,那么就把这条边加入最小生成树,这两个不同的集合就合并成了一个集合。如果这条边连接的两个点已经属于同一个集合,就跳过。知道选了n-1条边为止。
    用个图表示一下(和引例不一样)
    在这里插入图片描述

最终求得最小生成树权值为17(上图)

  • Kruskal算法的时间复杂度为O(E*logE),E为边数。
    小结
    通过上边的模拟能够看到,Kruskal算法每次都选择一条最小的且能合并两个不同集合的边,一张n个顶点的图总共选取n-1次边。因为我们每次选的都是最小的边,所以最后的生成树一定是最小生成树。
    每次我们选的边都能合并两个集合,最后n个点一定会合并成一个集合。
    通过这样的贪心策略,Kruskal算法能得到一棵有n-1条边,连接着n个顶点的最小生成树。
伪代码
// 把所有边排序,记第i小的边为e[i]
tot=0;// 初始化最小生成树为空
father[i]=i;// 初始化并查集,让每个点自成一个独立的连通分量
k=0;//计数器
for(int i=0;i<m;i++){
	if(e[i].u和e[i].v不在同一个连通分量里){
		//合并e[i].u和e[i].v所在的连通分量
		tot+=W(u,v);//把边加入最小生成树
		k++;//如果k=n-1,说明最小生成树已经生成,则break
	}
}

伪代码中最关键的部分在于连通分量的查询与合并:需要知道任意两点是否在同一个连通分量中,还需要合并两个连通分量。

关于查询与合并

最容易想到的方法是“暴力”。但是这个方法复杂而且效率不高。(需要写DFS或BFS)
有一种简介高效的方法可以用来处理这个问题:使用并查集

并查集

并查集的精妙之处就在于用树来表示集合。例如:若包含1、2、3、4、5、6的图有三个连通分量{1,3}、{2,5,6}、{4},则需要用三棵树来表示。这三棵树的具体形态无关紧要,只要有一体棵树包含1,3这两个点,一棵树包含2,5,6这三个点,还有一棵树只包含4这一个点即可。
如果把x的父节点保存在f[x]中(如果x没有父节点,则f[x]=x),那么不难写出“查找x所在树的的根节点”的递归方程:

int find(int x
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值