算法笔记-生成树

概念定义

图:由点和边组成的集合

生成图:图中删去若干个点和若干条边后剩下的子图

生成树:恰好为树的生成图

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

严格次小生成树:边权总和严格大于最小生成树且最小

 

最小生成树

Kruskal

Kruskal 是通过贪心法选边加入集合来求最小生成树的算法

 

算法过程

  • 把所有的点加入集合
  • 把所有的边按边权递增排序
  • 遍历每一条边,如果边的两个端点不连通,将此边加入集合,两个端点所在连通块合并
  • 重复 2, 3 步,直到所有点同属一个连通块

 

证明及实现

 感性的理解一下,我们最终要选择 n - 1 条边加入集合,那么肯定要选择边权尽可能少的。

 在第 3 步时,如果我们不选目前这条边,为了使两个连通块连通,一定会更劣,所以选择这条边就是最优的。

 实现的话,我们需要排序,为了维护连通块,还需要并查集。

 时间复杂度  O(M log M)

 

代码示例

 

Prim

Prim 是通过选点及其某一连边不断加入集合来求最小生成树的算法。

 

 算法过程

  • 将一个点加入集合
  • 将与集合中点连边权值最小的一个点及连边加入集合
  • 重复第 2 步,直到所有点都被加入集合

 

证明

 

红色的边已加入最小生成树

  

显然整张图每次被分为了集合内的点和非集合内的点,两个部分之间不连通。

那么使两个部分连通的最小代价就是两个部分之间的连边中权值最小的。

重复此过程求得的解显然是最优的。

 

代码示例

 

  

  

时间复杂度 O (n^2)

使用堆优化可到 O ((N + M) log N)

不过,一般使用 Prim 算法都是完全图,M 和 N^2 同阶,复杂度甚至不如朴素 Prim,所以此处只给出朴素代码。

 

Boruvka

Boruvka 是每次找到各个连通块之间的最短边来求解最小生成树的算法。

它的优势在于一些不给定边,而给出两点之间连边权值计算方式的图,它的效率会比较高。

不过仍是十分冷门的算法。

 

算法过程

  • 所有点都属于不同的连通块
  • 遍历每个连通块,找到它与其他连通块的最短边
  • 合并每个连通块与最短边相连的另一个连通块
  • 重复 2, 3 步,直到所有点同属一个连通块,结束

 

证明

可以看出这个算法是 Kruskal  Prim 的缝合怪。

正确性是显然的。

连通块数量每次都会减半,所以时间复杂度也是可过的。

 

代码示例

  

时间复杂度 O((N + M) log N)

 

(严格)次小生成树

 定理

一棵(严格)次小生成树一定和一棵最小生成树有且只有一条边的差别。

由定理可知,我们可以通过先求出最小生成树,在加边删边以求(严格)次小生成树。

 

算法过程

  •  求最小生成树
  • 枚举每一条不在最小生成树上的边,加入它到集合中。
  • 这时会出现一个环,找出环上权值最大的边(不能是刚加入的边),删去它,用目前的边权和更新答案。
  • 重复此过程得到的最大值即为次小生成树。

 

具体实现

我们来看一个例子:

例子

求出最小生成树后,再加入权值为 k 的边 u->v 后,出现了一个环,而我们需要知道的是树上 u->v 的简单路径上,最大的边权(如果求严格次小生成树,要求这个数不能为 k)。

发现可以用树剖维护,如果求非严格次小生成树,可以用 ST,严格的话最好用线段树。

线段树部分,需要维护最大值和严格次大值,具体请看代码。

 

代码示例

 

  

关于生成树的全部常用知识已经介绍完毕,如有问题请私信作者 @qkhm

(注:本文所有内容仅针对算法竞赛,如有不严谨还请海涵)

作者:qkhm

出处:https://www.cnblogs.com/qkhm/p/MakeTree.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   qkhm  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示