应用案例
来自机械工业出版社出版的《运筹学》教材第二版的应用案例10-8
荒地能源(WE)是一家天然气钻井公司,钻井位置位于其控制的一块荒地,公司目前想要修建连接各钻井之间的道路,下图展示了7个钻井的位置,以及两个钻井之间可能的道路线形与预期的构建费用(单位:千美元 )。只有位置1能够将其他位置与外界相连。WE希望选择一个总费用最小的道路集合,以生成一个每对位置间都存在一条路的网络。
该问题的最优解由粗线表示,其总费用为80k美元。
荒地能源需要的是如上图所示的一个最小生成树,它不包括任何环,但却能覆盖所有节点,同时这样的生成树还需要满足边权重的总和最小。
贪心算法可以用来寻找图中的最小生成树。而又可以根据出发点的不同,将贪心算法分为 “加边法” 和 “加点法”。
下面分别介绍两种求解最小(最大)生成树的贪心算法。
Kruskal’s Algorithm
Kruska’s Algorithm 的流程为:
- 将图中各边按照费用由小到大排列(求最大生成树时,费用需要由大到小排列),初始化生成树T=Ø
- 按照顺序遍历所有边,依次选择一条不会与生成树T里的其他边生成圈的边加入到当前生成树T中;如果当前边不满足要求,则跳过。
由上述算法流程可知,该算法的核心是完成“给定边的集合,是否能够组成圈的判断”。
如果从圈的定义(如下)入手进行判断,需要每个节点均搜索一遍,逻辑上会比较复杂。
- 每条弧和它的前一条弧恰有一个共同节点
- 没有节点会被重复访问
- 圈的起点和终止节点相同
因此,可以转换切入角度,从边和点的数量上进行判断。根据以下定理,只需要比较当前T∪arc之后的边数和顶点数,相等即为含圈,需要跳过当前arc。
在一个连通图G中,如果边数e等于顶点数v,那么图G中最多有一个圈
具体证明过程可以参考这里
python 实现
案例数据如下:
arcSet = {
(1,2):22,
(1,4):30,
(2,3):41,
(2,4):32,
(2,7):40