向世界分享科学之美,让科学流行起来
对于一个给定的连通无向图G=(V,E),其最小生成树被定义如下:取边集E中的子集E‘构成连通树,同时满足
,其中
表示边(集)的权值。
关于最小生成树的算法,有两个非常经典的算法Prim算法和Kruskal算法。这两种算法非常常见,同时实现也比较简单,具体实现过程可以通过百度等方式轻易获取,这里就不再赘述。本文将在这两种算法的基础上进一步讨论为什么这两种算法可以求出最小生成树?这两种算法背后所依据的理论是什么?因此,本文更加适合对该算法有一定了解,能够实现算法同时对进一步理解生成树算法感兴趣的读者。
Prim算法:
首先简述一下该算法的实现过程:对于边集E中的所有边e,该算法按照权值
从小到大的顺序遍历e。然后判断
e(u,v)中的两个端点u和v是否被已遍历的边连接在同一个连通子图中。如果未在同一个连通子图当中,则取该边将u和v所在的连通子图合并为一个连通子图。
要想证明该算法是正确的,可以通过证明如下性质进行讨论:
性质一:
客观来讲,对于任意
连通无向图
G,均存在至少一颗最小生成树。对于G的某棵最小生成树,可以通过割去其中的某些树边将G拆分成多个连通子图
,满足
。同时所有
均以构成最小生成子树。
求证对于连接不同的连通子图
和
的边集
,其中权值最小的边e满足
一定
在某一棵最小生成树当中。我们称
边e为轻边。
如图1是被分解成多个连通子图
的无向图,图中的边表示边集
中的所有边,其中边e4权值最小(轻边),用红线标出。
图1 无向图例子
证明:现用反证法证明上述问题。
假设存在一棵最小生成树不包含轻边
,即存在一棵最小生成树不包含边e4。
如图2所示,其中我们用橙色的线表示这样两棵最小生成树,并且为了方便起见,将其中的子图调整位置,使其变成以
为根的树状形式
。
其中包含了仅有两类不包含轻边的最小生成树例子。第一类,最小生成树中的边包含与轻边连接同样两个连通子图的边,如图2(a)中的边e3;第二类,
最小生成树中的边不包含与轻边连接同样两个连通子图的边,如图2(b)所示。
(a)
(b)
图2 两种不包含轻边的最小生成树
对于图
2(a)的情况。显然,对于连接两个连通子图而言,e3和e4是等价的。我们直接将e3置换成e4,可以得到一个更小的生成树。因此,
图
2(a)中所示的生成树并非最小生成树,与假设矛盾。
对于
图
2(b)的情况。设轻边e’连接的连通子图分别为
和
。显然,已构成的生成树中,必存在唯一一条路径连接
和
,而且该路径不包含
轻边e’。显然,在该路径两端再加上
轻边e’可得一个环,形如
。由于生成树中是不能包含环的,因此需要从该换中割去任意一条边构建新的生成树。割去该环中权值最大的边可以获得更小的生成树,显然这条边不是
轻边e’。因此,通过加入
轻边e’然后割去环中的最大权边能够获得更小的生成树,这同样与
最小生成树的假设矛盾。
因此,不
存在一棵最小生成树不包含轻边,即
轻边一定包含在某一棵最小生成树当中。
证明完毕。
根据此性质,再回过头来看Prim算法。在算法最初,连通图G的每个顶点都被单独分开在不同的连通子图当中,这些连通子图当然是由某个最小生成树切割而成的(准确讲是
最小生成树的所有边都被切割了)。
然后,对于
最小生成树切割而成的
连通子图集,算法从小到大判断E中的边是否在同一个集合中。显然,如果在同一个集合中则该边就不满足
的定义,反之就满足。而且,第一个找到的属于
的边就是所要求的轻边e‘。根据性质一,
轻边e‘在某个最小生成树中,由
e‘连接两个连通子图所构成的新子都满足
最小生成树切割而成的性质。由此可证明算法是正确的。
Kruskal算法
同样地,我们简述一下算法过程:该算法从G中的某个点出发构建连通子图。构建过程中,该连通子图都从与之相连接且不在
该连通子图中的点中寻找连接边权最小的点加入构成更大的连通子图,直到将所有点加入连通子图即获得最小生成树。
对于该算法的正确性,我们将进行以下论证:
如图3所示,
表示算法所构建的连通子图,由于该连通子图的存在,它将图G分割成若干块连通子图记为
。其中,不同的连通子图
和
中点
和
,连接u和v的路径必然包含
中的结点。图中直线表示
与所有
相连接的所有边,属于边集
。
其中权值最小的边e3(轻边)用红线标出。
图3 由
切割的连通子图图示
假设
是
某个最小生成树切割而成的连通子图。
由性质一,我们已经论证了在G被分割成多个连通子图后,各个连通子图的
轻边一定包含在某一棵最小生成树当中。因此,将轻边e’加入
后,
仍然是
某个最小生成树切割而成的连通子图。同时加入e‘后,也加入了一个原本不属于
的结点。从而新的
构成了一个更大的连通子图。
对于Kruskal算法,一开始
由一个点组成,它当然
是
某个最小生成树切割而成的连通子图。然后不断通过加入轻边得到一个更大的
,知道所有V中的点被加入
。在该过程中,
始终保持有
某个最小生成树切割而成的连通子图的性质。因此,算法运行结束后的
是一棵最小生成树。
最大生成树
与最小生成树相对应的还有最大生成树。对于最大生成树,只需将性质一中的轻边改成重边(权值最大的边)即可论证。因此,可证明Prim算法和Kruskal算法同样适用。