图论(八)最小生成树

来源:互联网 发布:上海美工 编辑:程序博客网 时间:2024/06/08 02:28

一个正在进行信息化建设的国家级贫困县,需要在下属9个乡镇之间架设光纤网络。为减少建设难度,光纤网主要沿着这9个乡镇之间互连的公路进行铺设。这9个乡镇之间的公路网以及相互之间的距离(单位:km)如下图所示:

如果你是工程师,该怎样设计线路铺设方案?当然,你可以直接把所有的公路网都铺设上光缆,这样的线路总长度是247公里。但如果你是这样想的,那么我一定会怀疑你到底是不是一名工程师!

你可以再设计一种方案,如下图中粗线条所示:

这种铺设方案的线路总长是161公里,这比前面的强多了。再进一步,你还可以得到2种更短的铺设线路:

这2种线路的总长分别是100km和95km。显然比前面的方案节省了更多。当然,这种线路方案你还可以列出很多。

在这个实际应用中,我们的目的,是要寻求一种连接图中所有节点的、成本最低的方式。本质上,再抽象一层,这是个组合优化问题,可以使用一些智能优化算法来解决。而在这个实例上,我们寻求使用更简单的图论方式解决。

当然,这是个老问题了,至少在20世纪初就已经提出了,它的解决方案最初是1926年由捷克数学家在构建一个电力网络的过程中首先提出来的。这种方式经常被用于架设电网、通信网、公路网、铁路网,甚至是架构某种形式的计算集群(这些任务都需要我们连接其中的每一个节点),也是解决旅行商问题的基础。

再回到这个问题本身,要包含图中所有的顶点n,同时代价最少,第一个想到的自然是减少边的数量,而要连接所有n个顶点,显然至少需要n-1条边。而我们知道一颗树(tree)就是n个顶点,n-1条边。

所以,这里引申出图论中的一个新概念:生成树(spanning tree)。含有图中全部n个顶点,以及包含图中某些n-1条边的一颗树是该图的生成树。有几个情况需要注意:

  • 图本身必须是无向连通图;
    如果是非连通图,那就不存在生成树的概念。我们知道树中任意2点都是连通的。如果是有向图,那也没有这个概念。
  • 生成树不止一种;
    生成树的n-1条边可以在图的边集合中选择,当然不止一种情况。
  • 每个生成树代价不同。
    一般使用生成树中边的权重值总和代表每个生成树的代价。
    而我们的工作就是要找到所有生成树中代价最小的,这就是最小生成树(minimum spanning tree)问题。

那么,我们构建最小生成树的时候,要从哪里着手呢?

首先,我们从边出发,先找到最短的边。

如上图所示,边e-i显然是最短的。最小生成树会不会一定包含这条边?根据上面的描述,生成树要包含所有的顶点,因此,生成树一定包含e,i两个顶点,所以也必然包含一条e,i之间的路径。我们随便构成一个生成树,见下图:

图中粗线条为构成的生成树,并不包含最短边e-i。e,i之间的路径是e-f-j-d-b-a-i,如果我们将边e-i加入这个生成树,必然构成环。

要消除这个环,从而构成新的生成树,我们可以移除e-f-j-d-b-a-i-e环路上除边e-i的其他任意一条边。例如,移除a-b或b-d。我们看看移除b-d,构成了一个新的生成树。

这个新的生成树与原先的生成树就差在一个包含边b-d,不包含边e-i,一个包含边e-i,不包含b-d。而新的生成树代价比原先的生成树代价低,因为边e-i是最短的,代价比边b-d要小。

因此,无论移除其他边中的哪条边,重新构成新的生成树都比最先的生成树代价小。因为哪条边的代价都比边e-i的代价要大。也就是说,任何不包含最短边的生成树结构都可以被做的更小。所以,最小生成树一定包含最短边。(后面的文章我们将看到,这也是最小生成树算法Kruskal的基本思想)。

其次,我们从顶点出发,来看看有什么新的结论。还是上面的图,我们以顶点b为例,根据生成树的定义,顶点b与其它顶点肯定是连通的。而顶点b有2条边,即边a-b,边b-d。这意味着最小生成树必然包含这2条边中的一个。而边b-d比a-b要短,因此选择b-d是否更合理?

我们用反证法证明下,假设选择较长的边a-b是更好的选择,即最小生成树包含a-b这条边。我们把边b-d也加入这个生成树,形成了一个环。在这个环中,如果移除边a-b,那么得到的新生成树代价比以前的要小,这与假设的选择较长边更好相矛盾。所以在b点选择较短的边才有可能生成最小生成树。(后面的文章我们将看到,这也是最小生成树算法Prim的基本思想)。

参考文献:

1.《大话数据结构》 程杰 清华大学出版社
2.《Python算法教程》Magnus Lie Hetland 人民邮电出版社

原创粉丝点击