最小生成树

最小生成树

在一个连通网的所有生成树中,各边的代价之和最小的那棵生成树称为该连通网的最小代价生成树(Minimum Cost Spanning Tree),简称为最小生成树。最小生成树有如下重要性质:

设 N=(V,{E}) 是一连通网,U 是顶点集V的一个非空子集。若(u , v)是一条具有最小权值的边,其中u∈U,v∈V-U,则存在一棵包含边(u , v)的最小生成树。

我们用反证法来证明这个性质:

假设不存在这样一棵包含边(u , v)的最小生成树。任取一棵最小生成树T,将(u , v)加入T中。根据树的性质,此时T中必形成一个包含(u , v)的回路,且回路中必有一条边(u , v)的权值大于或等于(u , v)的权值。删除(u , v),则得到一棵代价小于等于T的生成树T’,且T’为一棵包含边(u , v)的最小生成树。这与假设矛盾。

这个性质被称为MST性质。我们可以利用MST性质来生成一个连通网的最小生成树。普利姆(Prim)算法和克鲁斯卡尔(Kruskal)算法便是利用了这个性质。

下面分别介绍这两种算法。

1.     普利姆算法

假设N=(V,{E})是连通网,TE为最小生成树中边的集合

(1)初始U={u0}(u0∈V),TE=φ;

(2)在所有u∈U, v∈V-U的边中选一条代价最小的边(u0,v0)并入集合TE,同时将v0并入U;

(3)重复(2),直到U=V为止。

此时,TE中必含有n-1条边,则T=(V,{TE})为N的最小生成树。

可以看出,普利姆算法逐步增加U的中顶点,可称为“加点法”。

注意:选择最小边时,可能有多条同样权值的边可选,此时任选其一。

为了实现这个算法需要设置一个辅助数组closedge[ ],以纪录从U到V-U具有最小代价的边。对每个顶点v∈V-U,在辅助数组中存在一个分量closedge[v],它包括两个域vex和lowcost,其中lowcost存储该边上的权,显然有

       closedge[v].lowcoast=Min({cost(u,v) | u∈U})

普里姆算法可描述如下:

struct {

    VertexData  adjvex;

    int         lowcost;

} closedge[MAX_VERTEX_NUM];   /* 求最小生成树时的辅助数组*/

 

 

MiniSpanTree_Prim(AdjMatrix  gn,  VertexData  u)

/*从顶点u出发,按普里姆算法构造连通网gn 的最小生成树,并输出生成树的每条边*/

{

k=LocateVertex(gn, u);

closedge[k].lowcost=0;   /*初始化,U={u} */

for (i=0;i<gn.vexnum;i++)    

  if ( i!=k)    /*对V-U中的顶点i,初始化closedge[i]*/

    {closedge[i].adjvex=u; closedge[i].lowcost=gn.arcs[k][i].adj;}

for (e=1;e<=gn.vexnum-1;e++)    /*找n-1条边(n= gn.vexnum) */

{

k0=Minium(closedge);     /* closedge[k0]中存有当前最小边(u0,v0)的信息*/

u0= closedge[k0].adjvex;   /* u0∈U*/

v0= gn.vexs[k0]          /* v0∈V-U*/

       printf(u0, v0);    /*输出生成树的当前最小边(u0,v0)*/

       closedge[k0].lowcost=0;     /*将顶点v0纳入U集合*/

       for ( i=0 ;i<vexnum;i++)    /*在顶点v0并入U之后,更新closedge[i]*/

         if ( gn.arcs[k0][i].adj <closedge[i].lowcost)

            { closedge[i].lowcost= gn.arcs[k0][i].adj;

              closedge[i].adjvex=v0;

        } 

}

   }

                    算法 7.9  普里姆算法

由于算法中有两个for循环嵌套,故它的时间复杂度为O(n2)。

利用该算法,对图7.18(a)所示的连通网从顶点V1开始构造最小生成树,算法中各参量的变化如表7-1所示




图 7.18 普里姆算法构造最小生成树的过程

表7-1  普里姆算法各参量的变化


i

 

Closedge[i]

 

0

 

1

 

2

 

3

 

4

 

5

 

U

 

V-U

 

e

 

 

k0

 

(u0, v0)

adjvex

lowcost

 

0

V1

6

V1

1

V1

5

V1

V1

{V1}

{V2,V3,V4,V5,V6}

 

1

 

2

 

(V1, V3)

adjvex

lowcost

 

0

V3

5

 

0

V1

5

V3

6

V3

4

{V1,V3}

{V2,V4,V5, V6}

 

2

 

5

 

(V3, V6)

adjvex

lowcost

 

0

V3

5

 

0

V6

2

V3

6

 

0

{V1,V3,V6}

{V2,V4,V5}

 

3

 

3

 

(V6, V4)

adjvex

lowcost

 

0

V3

5

 

0

 

0

V3

6

 

0

{V1,V3,V6, V4}

{V2,V5}

 

4

 

1

 

(V3, V2)

adjvex

lowcost

 

0

 

0

 

0

 

0

V2

3

 

0

{V1,V3,V6, V4,V2}

{V5}

 

5

 

4

 

(V2, V5)

adjvex

lowcost

 

0

 

0

 

0

 

0

 

0

 

0

{V1,V3,V6,V4,V2,V5}

{ }

 

 

 

 


















2.         克鲁斯卡尔算法

假设N=(V,{E})是连通网,将N中的边按权值从小到大的顺序排列;

①    将n个顶点看成n个集合;

②    按权值小到大的顺序选择边,所选边应满足两个顶点不在同一个顶点集合内,将该边放到生成树边的集合中。同时将该边的两个顶点所在的顶点集合合并;

③    重复②直到所有的顶点都在同一个顶点集合内。

可以看出,克鲁斯卡尔算法逐步增加生成树的边,与普利姆算法相比,可称为“加边法”。

例如,对于图7.17所示的连通网,将所有的边按权值从小到大的顺序排列为:

权值    1      2        3        4        5        5        5       6        6       6

边  (V1,V3)  (V4,V6)  (V2,V5)  (V3,V6)  (V1,V4)  (V2,V3)  (V3,V4)  (V1,V2)  (V3,V5)  (V5,V6)

经过筛选所得到边的顺序为:

(V1,V3),(V4,V6),(V2,V5),(V3,V6),(V2,V3)

    在选择第五条边时,因为V1、V4已经在同一集合内,如果选(V1,V4),则会形成回路,所以选(V2,V3)。

下面我们以图7.19(a)中的连通网为例,详细说明克鲁斯卡尔算法的执行过程。

      7.19 克鲁斯卡尔算法执行示意图



(1)待选的边:

   (2,3)->5 , (2,4)->6 , (3,4)->6 , (2,6)->11 , (4,6)->14 , (1,2)->16 , (4,5)->18 , (1,5)->19,

   (1,6)->21 , (5,6)->23。

  顶点集合状态:{1},{2},{3},{4},{5},{6}

  最小生成树的边的集合: {  }。

(2从待选边中选一条权值最小的边为: (2,3)->5。

  待选的边变为:(2,4)->6 , (3,4)->6 , (2,6)->11 , (4,6)->14 , (1,2)->16 , (4,5)->18 , (1,5)->19, (1,6)->21 , (5,6)->23。

  顶点集合状态变为: {1},{2,3},{4},{5},{6}。

  最小生成树的边的集合:{(2,3)}。

(3)从待选边中选一条权值最小的边为: (2,4)->6;

  待选的边变为:(3,4)->6 , (2,6)->11 , (4,6)->14 , (1,2)->16 , (4,5)->18 , (1,5)->19, (1,6)->21 , (5,6)->23。

  顶点集合状态变为:{1},{2,3,4},{5},{6}。

  最小生成树的边的集合 {(2,3),(2,4)}。

(4)从待选边中选一条权值最小的边为:(3,4)->6,由于3、4在同一个顶点集合{2,3,4}内,故放弃。重新从待选边中选一条权值最小的边为:(2,6)->11。

  待选的边变为:(4,6)->14 , (1,2)->16 , (4,5)->18 , (1,5)->19, (1,6)->21 , (5,6)->23。

  顶点集合状态变为: {1},{2,3,4,6},{5}。

  最小生成树的边的集合 {(2,3),(2,4),(2,6)}。

(5)从待选边中选一条权值最小的边为:(4,6)->14,由于4、6在同一个顶点集合{2,3,4,6}内,故放弃。重新从待选边中选一条权值最小的边为:(1,2)->16。

  待选的边变为:(4,5)->18 , (1,5)->19, (1,6)->21 , (5,6)->23。

  顶点集合状态变为: {1,2,3,4,6},{5}。

  最小生成树的边的集合: {(2,3),(2,4),(2,6),(1,2)}。

(6)从待选边中选一条权值最小的边为: (4,5)->18。

  待选的边变为:     (1,5)->19, (1,6)->21 , (5,6)->23。

  顶点集合状态变为: {1,2,3,4,6,5}。

  最小生成树的边的集合 {(2,3),(2,4),(2,6),(1,2),(4,5)}。



至此,所有的顶点都在同一个顶点集合{123465}里,算法结束。所得最小生成树如图7.20所示,其代价为:5+6+11+16+18=56


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值