首页 > 代码库 > 关于最小生成树问题

关于最小生成树问题

       我们通过一个例子来看一下最小生成树的求法。

       分别用普里姆算法(从A结点开始)和克鲁斯卡尔算法计算下图的最小生成树。

 

       ok,首先运用Prim算法进行计算:

UV-UBCDEFTE
{A}{B,C,D,E,F}AB
11
AC
13
~
AE
16
~
AB
11
{A,B}{C,D,E,F} BC
7
BD
3
AE
16
BF
5
BD
3
{A,B,D}{C,E,F} BC
7
 AE
16
BF
5
BF
5
{A,B,D,F}{C,E} BC
7
 FE
12
 BC
7
{A,B,D,F,C}{E}   FE
12
 FE
12
{A,B,D,F,C,E}{}      
        图表可能看着有点乱,没关系,我们先来看一下Prim算法的基本思想:假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:在所有u∈U, v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。

       那么对照例图和表格我们就很容易地可以看出该算法的计算流程,首先从结点A开始,分别写出与其他结点的路径和权值,如果不连通则取权值为无穷,于是就有了表格的第二行,TE取代价最小的AB;然后将B添加到U,写出结点B与其他结点的路径和相应的权值,当然A就不用再写了,大家可以看到,凡是添加到最小生成树中的路径,之后该列则为空,因为它已经是代价最小的边,不可能再有其他边比它更小了;还有一个问题。为了方便起见,在同一列中,如果对应边的权值不小于其前一个,则将其直接落下来,这样就可以只比较那个“更小的”,这样就不用每一行都去比较了;按照这个思路,表格的第三行,BD的权值为3,小于其前一个的权值无穷,则写入3;第五行,FE的权值为12,小于其前一个AE的权值16,所以写入12;其实每一行和每一列都是在找那个代价最小的路径,这样求得的集合就是最小生成树,当然还得加入结点的集合,这样所示表格也就不难理解了,每一行找到一条代价最小的路径,加入TE,然后将结点加入U,再去比较其他的路径,就这样一直走下去,最后得到最小生成树集合。

       接下来进入克鲁斯卡尔算法:

       首先看一下它的基本思想:先构造一个只含 n 个顶点的子图 SG,然后从权值最小的边开始,若它的添加不使SG 中产生回路,则在 SG 上加上这条边,如此重复,直至加上 n-1 条边为止。一句话,“不构成环的情况下,每次选取最小边” 。它的出发点就是为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能地小。因此我们就从权值最小的边开始构造,前提是不构成环。

       那么我们直接从图中找权值最小的边进行组合,首先是BD,然后是BF,BC,CF不行,因为其构成了环,AB可以,EF也可以,ok,这样就得到了最小生成树边的集合TE={BD,BF,BC,AB,EF},是不是比Prim算法简单的多?!

      所以该图的最小生成树可以表示为T=({A,B,D,F,C,E},{BD,BF,BC,AB,EF}),当然最好还是可以画出图来,这样会更加直接明了。