最小生成树(Minimum Spanning Tree)及生成MST的几种方法

最小生成树 (Minimum Spanning Tree)

最小生成树是图论领域的一个基本概念,适用于加权连通图,其中包括若干顶点(节点)以及连接这些顶点的边(边可以有权重)。在一个加权连通图中,生成树(Spanning Tree)是一个无环子图,它包含图中的所有顶点,并且用最少数量的边将它们连接起来。注意,无环是指子图中不存在任何边的闭环,最少数量的边意味着任意两个顶点之间有且仅有一条路径相互到达。

“最小生成树”这一术语的“最小”指的是在所有可能的生成树中,边的权重之和最小的那一个。在实际应用中,最小生成树可以帮助找到在网络设计、电路设计等方面成本最低的方案。

我们来举一个简单的例子。假设有四个城市,每两个城市之间可以修建道路相连,不同的道路成本不同,现在的目标是花最少的成本将这四个城市全部连通。最小生成树算法即是解决此类问题的有效工具。

生成最小生成树的算法

接下来,我们将介绍四个生成最小生成树的经典算法,它们分别是克鲁斯卡尔(Kruskal)算法和普里姆(Prim)算法,以及相对少见的Borůvka算法和Sollin算法。

1. 克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔算法是基于边的贪心策略。它的基本思想是按照边权重从小到大的顺序选择边,从而构造最小生成树。选取的边必须满足添加后不形成环路。

伪代码:
KRUSKAL(G):
  A = ∅                            // A将存储最小生成树的边
  对于G中的每个顶点v:
    MAKE-SET(v)
  将G中的所有边按权重由低到高排序
  对于每条边(u, v)按序做如下操作:
    if FIND-SET(u) ≠ FIND-SET(v):   // 检查u和v是否在树的不同分量中
      A = A ∪ {(u, v)}               // 将边(u, v)加入到A中
      UNION(u, v)                    // 将u和v的分量合并
  返回A

其中 MAKE-SET、FIND-SET 和 UNION 是不相交集合数据结构的操作,用于维护和查询顶点间是否存在环路。

2. 普里姆(Prim)算法

普里姆算法是基于点的贪心策略。在这个算法中,我们从任选的一个顶点开始构建最小生成树,逐步扩大树的范围,每一步都添加一条连接树与非树顶点且权重最小的边。

伪代码:
PRIM(G, w, r):                     // G是图,w是权重函数,r是开始顶点
  for each u ∈ G.V:
    u.key = ∞                      // 初始化所有顶点的键值为无穷大
    u.π = NIL                       // π属性用来记录最小生成树的父节点
  r.key = 0
  Q = G.V
  while Q ≠ ∅:
    u = EXTRACT-MIN(Q)             // 从Q中取出键值最小的顶点u
    for each v ∈ G.Adj[u]:         // 遍历u的所有邻居v
      if v ∈ Q and w(u, v) < v.key:
        v.π = u                     // 更新v的父节点为u
        v.key = w(u, v)             // 更新v的键值为u与v之间边的权重

在Prim算法中,EXTRACT-MIN(Q)是优先队列的操作,它用于选择权重最小的边,而G.Adj[u]表示图中与顶点u相邻的所有顶点集合。

3. Borůvka算法

Borůvka算法是最早的最小生成树算法之一,适用于稀疏图。算法的每个阶段为图中的每个连通分量选择一条权重最小的边,并将这些边添加到生成树中,直到图变为连通的。

伪代码:
BORUVKA(G):
  forest = each vertex in G is a separate tree
  while there is more than one tree in the forest:
    for each tree T in the forest:
      find the smallest edge connecting T to another tree
      add this edge to the forest
  return the edges added to the forest
4. Sollin算法

Sollin算法(也被称为Borůvka的改进版本)同样适用于稀疏图,其基本想法是在每个阶段找到每个连通分量键值最小的边,并将它们加入生成树,像Borůvka算法一样重复这个过程,直到所有分量合并到一起。

伪代码:
SOLLIN(G):
  Initialize a forest F with each vertex in G as a separate tree
  while F has more than one tree do
    for each tree T in the forest F do
      let e = the lightest edge with one end in T
      if there is no edge chosen for T or e is lighter than the already chosen edge
        choose e for T
    for each edge e chosen in this round do
      if e connects two different trees then
        add e to the forest F
  return the forest F as the minimum spanning tree

在Sollin算法中,检查加入边e后是否会造成环路的操作通过查询树的根节点来实现,保证了每次迭代加入的边一定属于不同的连通分量。

如果你想更深入地了解人工智能的其他方面,比如机器学习、深度学习、自然语言处理等等,也可以点击这个链接,我按照如下图所示的学习路线为大家整理了100多G的学习资源,基本涵盖了人工智能学习的所有内容,包括了目前人工智能领域最新顶会论文合集和丰富详细的项目实战资料,可以帮助你入门和进阶。

链接: 人工智能交流群(大量资料)

在这里插入图片描述

你可能感兴趣的:(算法)