加权图能够自然的表示许多应用,比如航空图中,点可以表示起始地,边表示航线,边权可以表示距离或者费用。网络图中,点可以表示网络中的节点,边表示那些节点直接相连,边权可以表示费用或者信号传输时间。在这些问题中,一个很常见且重要的问题是将成本最小化。
即:给定一幅加权无向图,找到它的一棵最小生成树。
定义
图的 生成树
是它的一棵含有其所有顶点的无环连通子图。
一幅加权图的 最小生成树(MST)
是它的一棵权值(树中所有边的权值之和)最小的生成树。
约定
- 只考虑连通图
- 权值可能是 0 或者负数
- 所有边的权值各不相同。(作此约定是为了保证产生的生成树唯一以简化证明,实际算法也能处理等边权的情况。)
算法
树的性质
- 连接树中任意两个顶点都会产生一个新的环
- 从树中删去一条边将会得到两棵独立的树
定义
图的一种 切分
是将图的所有顶点分为两个非空且不重叠的两个集合。
横切边
是一条连接两个属于不同集合的顶点的边。
切分定理
在一幅加权图中,给定任意的切分,它的横切边中的权重最小者必然属于图的最小生成树。
证明: 令 e 为权重最小的横切边, T为图的最小生成树。我们采用反证法: 假设 T 不包含e 。 那么如果将 e 加入T , 得到的图必然含有一条经过 e的环, 且这个环至少含有另一条横切边--设为f , f 的权重必然大于e (因为e 的权重是最小的且图中所有边的权重均不同)。那么我们 f删掉 e就保留 可以得到一棵权重更小的生成树。这和我们的假设 T 矛盾。
在权重均不相同的前提下,每幅连通图都只有唯一的最小生成树,切分定理表明了对于每一种切分,权重最小的边必然属于最小生成树。
贪心算法
下面这种方法会将含有V 个顶点的任意加权连通图中属于最小生成树的边标记为黑色:
初始状态下所有边均为灰色, 找到一种切分, 它产生的横切边均不为黑色。将它权重最小的横切边标记为黑色。不断反复, 直到标记了 V-1条黑色边为止。
证明:为了简单, 我们假设所有边的权重均不相同, 尽管没有这个假设该命题同样成立。根据切分定理,所有被标记为黑色的边均属于最小生成树。如果黑色边的数量小 于V-1 , 必然还存在不会产生黑色横切边的切分(因为我们假设图是连通的)。只要找到了 V-1条黑色的边,这些边所组成的就是一棵最小生成树。
接下来要学习的 Prim 算法和 Kruskal 算法是对上诉贪心算法的具体实现,其区别在于以不同的方式找到符合要求的切分。
Prim 算法
Prim 算法的每一步都会为一棵生长中的树添加一条边。一开始这棵树只有一个顶点,然后会向它添加V-1 条边,每次总是将下一条连接树中的顶点与不在树中的顶点且权值最小的边加入树中 (即由树中已加入 MST 的顶点和未加入 MST 的顶点所构成的切分的一条横切边)。
证明:这棵不断生长的树定义了一个切分且不存在黑色的横切边。该算法会选取权值最小的横切边并根据贪心算法不断将它们标记为黑色。
Kruskal 算法
Kruskal 算法总是维护无向图的最小生成森林。 最初, 可认为生成森林由零条边构成, 每个节点各自构成一棵仅包含一个点的树。
在任意时刻, Kruskal 算法从剩余的边中选出一条权值最小的,并且这条边的两个 端点属于生成森林中两棵不同的树 (不连通), 把该边加入生成森林。图中节点的连通 情况可以用并查集维护。 详细来说, Kruskal 算法的流程如下:
- 建立并查集, 每个点各自构成一个集合。
- 把所有边按照权值从小到大排序,依次扫描每条边(x,y,z) 。
- 若x,y 属于同一集合 (连通), 则忽略这条边, 继续扫描下一条。
- 否则, 合并 x,y 所在的集合, 并把z 累加到答案中。
- 所有边扫描完成后,第 4 步中处理过的边就构成最小生成树。 时间复杂度为 O(m log m) 。
总结
Kruskal 算法的时间复杂度为 O(m log m)。主要开销是排序。
Prim 算法的时间复杂度为 O(),可以通过优先队列优化到 o(m log m),但用优先队列不如直接使用 Kruskal 算法方便。因此,Prim 主要用于稠密图,尤其是完全图的最小生成树的求解。