已跳过全部重新生成_【朝夕的ACM笔记】图论-最小生成树

【朝夕的ACM笔记】目录与索引

最小生成树

一、基本概念

连通图:图中的任意两个节点都是相通的。

生成树:连通图的一个连通子图,其含有全部

个节点,但仅有
条边。

最小生成树:边权和最小的生成树。

通俗地说,给定

个点,
条边,从其中选取若干条边,使得产生的图为连通图,且边权和最小,这张图就是最小生成树。

下面介绍两种最小生成树的求法。

二、Kruskal算法

2.1 算法思想

Kruskal(克鲁斯卡尔)算法的基本思想如下:

①对所有给的边按其边权进行从小到大的排序。

②顺序遍历排序后的边。

③若当前边连接的两个节点已经在生成树上了,则跳过这条边。

④否则则将这条边加入生成树。

⑤当生成树上边数达到

条时,结束算法,此时生成树就是最小生成树。

由于需要判断两个节点是否已经连通,所以Kruskal算法还需要用到并查集。

Kruskal算法的时间复杂度为

,主要是对边排序的时间复杂度,正因如此,该算法在面对稀疏图(边数较少)时,效果较好。

2.2 参考代码

以下为【洛谷:P3366 最小生成树】的AC代码。

#include 

三、Prim算法

3.1 算法思想

如果说Kruskal算法是基于边的算法,那么Prim算法则是基于点的算法。

Prim算法的基本思想如下:

①将任意一个点先加入生成树中。

②寻找这样的一个点,它尚未加入生成树,但与生成树内的点有边相连,且此边是所有满足条件的边中边权最小的。

③把这个点加入生成树,边权和加上这条边,然后重复②。

④直到所有点都加入生成树后,结束算法。

为了易于理解,我们举个例子来说明:

329619e780f54474bdea8a361980b897.png

在上图中,我们重复一遍Prim的流程。

①将1加入生成树,此时生成树内节点为{1},边权和为0。

②与生成树内节点相连的未加入节点有2和3,最小权边为1-3,权为1。

③将3加入生成树,此时生成树内节点为{1,3},边权和为1。

④与生成树内节点相连的未加入节点有2,4,5,最小权边为1-2(或3-4),权为2。

⑤将2加入生成树,此时生成树内节点为{1,2,3},边权和为3。

⑥与生成树内节点相连的未加入节点有4,5,最小权边为3-4,权为2。

⑦将4加入生成树,此时生成树内节点为{1,2,3,4},边权和为5。

⑧与生成树内节点相连的未加入节点有5,最小权边为3-5,权为5。

⑨将5加入生成树,此时生成树已含全部节点,边权和为10,结束算法。

3.2 参考代码

要将以上步骤写成代码,则需要有一点点的改动。

我们每次加入点时,都将与该点连接的点其最小距离更新。

找点时就只需要遍历一遍所有未访问点就可以找到步骤②中的那个点了。

代码的时间复杂度是

,与边数基本无关(更新时遍历边的部分基本可忽略),所以对稠密图(边数较多)效果较好。

以下为【洛谷:P3366 最小生成树】的AC代码。

#include

3.3 优先队列优化算法

我们会发现以下的代码本质是在找最小点:

for

所以我们可以使用优先队列来维护最小点。

注:我个人感觉Prim算法和最短路的Dijkstra算法是非常相像的,包括使用优先队列来优化这一点。

以下是优先队列维护Prim算法的参考代码,因为优先队列本质是由堆实现的,所以我称之为Prim_Heap。

Prim_Heap的时间复杂度为

#include

四、各算法的时间复杂度分析

注:引用博文https://blog.csdn.net/gykimo/article/details/8538275。

① Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。

②Prim_Heap在任何时候的时间复杂度都要优于朴素Prim和Kruskal(因为一般图的边数总是大于节点数的),但优先队列维护的代价是更大的内存空间使用。

③一般情况就使用Prim_Heap吧。

五、相关例题

5.1 买礼物 洛谷 P1194

5.2 口袋的天空 洛谷 P1195

5.3 最短网格 洛谷 P1546

5.4 爆弹虐场 洛谷 P2798

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值