最小生成树(最小支撑树)算法

\qquad 在上篇文章中,我介绍了网络模型中的一些相关概念,在这篇文章,我将介绍网络模型中的最小生成树算法,又叫最小支撑树算法。

最小生成树(最小支撑树)算法

0 原理

        最小生成树算法的作用是连接一个网络的所有节点,使树上边的总长度达到最小
两个例子:

  1. 需要在几个城镇之间修路,使得任意两个城镇都有路相连,中间可以穿过一个或者多个其他城镇,这时需要一个修路方案使修路的里程最小。
  2. 某海湾上需要设计一个海面上的天然气管道网路,将各个井口连接到岸边的运输点,设计的目标是最小化修建管道的费用。

        最小生成树算法原理其实很简单:把节点分为已连接节点、未连接节点,在未连接节点中选一个节点 t t t,使得 t t t到已连接节点中某个节点的弧长最小。其实主要使用的思想还是贪心思想,从第一个节点开始,每次从未选节点中选一个节点,让该节点到已选节点中的路径最短,并将另一端的节点放入已选接节点中。

1 步骤

最小生成树的具体步骤是:

<1> 令N={1, 2, …, n},为网络中节点的集合,定义:
C k = 在 第 k 步 时 已 连 接 的 节 点 集 合 C k ‾ = 在 第 k 步 以 后 需 要 连 接 的 节 点 集 合 ( 未 连 接 或 待 连 接 的 节 点 ) C_k=在第k步时已连接的节点集合 \\ \overline{C_k}=在第k步以后需要连接的节点集合(未连接或待连接的节点) Ck=kCk=k

<2> 第0步:令 C 0 = ∅ , C 0 ‾ = N C_0=\emptyset,\overline{C_0}=N C0=C0=N.

<3> 第1步:从 C 0 ‾ \overline{C_0} C0中的任意一个节点 i i i开始,令 C 1 = { i } C_1=\{i\} C1={i},那么 C 1 ‾ = N − { i } \overline{C_1}=N-\{i\} C1=N{i}.设定 k = 2 k=2 k=2.

<4> 一般的第 k k k步:在还没连接的节点集合 C ‾ k − 1 \overline{C}_{k-1} Ck1中选择一个节点 t ∗ t^* t,使得 t ∗ t^* t C ‾ k − 1 \overline{C}_{k-1} Ck1中某个节点之间的弧长最小,然后将 t ∗ t^* t放入 C k − 1 C_{k-1} Ck1中,并将 t ∗ t^* t C ‾ k − 1 \overline{C}_{k-1} Ck1中删除,即:
C k = C k − 1 + { t ∗ } C k ‾ = C ‾ k − 1 − { t ∗ } C_k = C_{k-1} + \{t^*\} \\ \overline{C_k} = \overline{C}_{k-1} - \{t^*\} Ck=Ck1+{t}Ck=Ck1{t}
<5> 停止条件:如果未连接节点的集合 C k ‾ \overline{C_k} Ck是空集,则停止。否则,设定 k = k + 1 k=k+1 k=k+1,重复<4>。

2 栗子

        某地的5个城镇需要铺设天然气管道,下图中给出了5个城镇之间可以铺设管道的情况的以及距离,先求一个设计方案,用最短的管道将5个城镇连接起来。
在这里插入图片描述

解题过程
\qquad 从节点1开始(可以选择其他任意一个节点),则 C 1 = { 1 } , C 1 ‾ = { 2 , 3 , 4 , 5 , 6 } C_1=\{1\},\overline{C_1}=\{2,3,4,5,6\} C1={1}C1={2,3,4,5,6}.下图中将为连接的点与已连接的点分为两个区域,并用线表示所有连接集合 C 1 , C 1 ‾ C_1,\overline{C_1} C1C1的侯选边,其中,红线表示的是所有候选边中最短的一条,令集合R存储每次选取的弧。开始迭代。

迭代1: 由图可见,边(1,2)是所有候选边中最短的一条,则确定节点2为下一连接节点,得到 C 1 = { 1 , 2 } , C 1 ‾ = { 3 , 4 , 5 , 6 } , R 1 = { ( 1 , 2 ) } C_1=\{1,2\},\overline{C_1}=\{3,4,5,6\},R_1=\{(1,2)\} C1={1,2}C1={3,4,5,6}R1={(1,2)}

在这里插入图片描述
迭代2: 边(2,5)是所有候选边中最短的,则确定节点3为下一连接节点,得到 C 2 = { 1 , 2 , 5 } , C 2 ‾ = { 3 , 4 , 6 } , R 2 = { ( 1 , 2 ) , ( 2 , 5 ) } C_2=\{1,2,5\},\overline{C_2}=\{3,4,6\},R_2=\{(1,2),(2,5)\} C2={1,2,5}C2={3,4,6}R2={(1,2),(2,5)}.其中,黑线表示已经连接的边。
在这里插入图片描述
迭代3: 边(2,4)是所有候选边中最短的,则确定节点4为下一连接点,得到 C 3 = { 1 , 2 , 5 , 4 } , C 3 ‾ = { 3 , 6 } , R 3 = { ( 1 , 2 ) , ( 2 , 5 ) , ( 2 , 4 ) } C_3=\{1,2,5,4\},\overline{C_3}=\{3,6\},R_3=\{(1,2),(2,5),(2,4)\} C3={1,2,5,4}C3={3,6}R3={(1,2),(2,5),(2,4)}.
在这里插入图片描述
迭代4: 边(4,6)是所有候选边中最短的,则确定节点6为下一连接点,得到 C 4 = { 1 , 2 , 5 , 4 , 6 } , C 4 ‾ = { 3 } , R 4 = { ( 1 , 2 ) , ( 2 , 5 ) , ( 2 , 4 ) , ( 4 , 6 ) } C_4=\{1,2,5,4,6\},\overline{C_4}=\{3\},R_4=\{(1,2),(2,5),(2,4),(4,6)\} C4={1,2,5,4,6}C4={3}R4={(1,2),(2,5),(2,4),(4,6)}.

在这里插入图片描述
迭代5: 边(1,3)和边(4,3)是所有候选边中最短的任选其中的一条,这里我们选(1,3),则确定节点3为下一连接点,得到 C 5 = { 1 , 2 , 5 , 4 , 6 , 3 } , C 5 ‾ = { } , R 5 = { ( 1 , 2 ) , ( 2 , 5 ) , ( 2 , 4 ) , ( 4 , 6 ) , ( 1 , 3 ) } C_5=\{1,2,5,4,6,3\},\overline{C_5}=\{\},R_5=\{(1,2),(2,5),(2,4),(4,6),(1,3)\} C5={1,2,5,4,6,3}C5={}R5={(1,2),(2,5),(2,4),(4,6),(1,3)}.

在这里插入图片描述
最终得到的路线是:R={(1,2),(2,5),(2,4),(4,6),(1,3)},长度为:1+3+4+3+5=16.如下图

在这里插入图片描述

\qquad 其实最小生成树又叫最小支撑树,不同教材或者书籍的叫法不同,比如人民邮电出版社出版的《运筹学导论》中叫“最小生成树”,而科学出版社出版的《运筹学(第三版)》中叫“最小支撑树”。而最小生成树的生成算法也有很多,其中比较常用的是破圈法和避圈法,而上面介绍的算法即避圈法

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
普利姆算法是一种用于求解无向图的最小生成树的基本算法。它以一个起始节点开始,每次将一个未被访问的节点加入到最小生成树集合中,并选择与该集合相邻的边中权重最小的边和它连接的未访问节点,直到最小生成树集合包含了图中的所有节点。普利姆算法的时间复杂度为O(n^2)。 以下是普利姆算法的步骤: 1. 选择一个起始节点作为最小生成树的起点。 2. 将该起始节点加入最小生成树集合,并将其标记为已访问。 3. 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点。 4. 将该边和节点加入最小生成树集合,并将该节点标记为已访问。 5. 重复步骤3和步骤4,直到最小生成树集合包含了图中的所有节点。 以下是Python实现普利姆算法的代码: ```python def prim(graph): # 选择一个起始节点作为最小生成树的起点 start_node = list(graph.keys())[0] # 将该起始节点加入最小生成树集合,并将其标记为已访问 visited = [start_node] # 初始化最小生成树的权重为0 min_weight = 0 # 初始化最小生成树的边为空 min_tree = [] # 重复步骤3和步骤4,直到最小生成树集合包含了图中的所有节点 while len(visited) < len(graph): # 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点 min_edge = None for node in visited: for neighbor, weight in graph[node].items(): if neighbor not in visited: if min_edge is None or weight < min_edge[2]: min_edge = (node, neighbor, weight) # 将该边和节点加入最小生成树集合,并将该节点标记为已访问 visited.append(min_edge[1]) min_weight += min_edge[2] min_tree.append(min_edge) # 返回最小生成树的权重和边 return min_weight, min_tree ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值