您的位置:首页 > 编程语言 > Python开发

最小生成树,普里姆算法(Python实现)

2015-12-16 13:46 519 查看
December 16, 2015 12:01 PM

1.相关概念

1)生成树 一个连通图的生成树是它的极小连通子图,在n个顶点的情形下,有n-1条边。生成树是对连通图而言的,是连同图的极小连通子图,包含图中的所有顶点,有且仅有n-1条边。非连通图的生成树则组成一个生成森林;若图中有n个顶点,m个连通分量,则生成森林中有n-m条边。

2)和树的遍历相似,若从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历, (Traversing Graph)。图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。图的遍历顺序有两种:深度优先搜索(DFS)和广度优先搜索(BFS)。对每种搜索顺序,访问各顶点的顺序也不是唯一的。

3)在一个无向连通图G中,其所有顶点和遍历该图经过的所有边所构成的子图G′ 称做图G的生成树。一个图可以有多个生成树,从不同的顶点出发,采用不同的遍历顺序,遍历时所经过的边也就不同。

在图论中,常常将树定义为一个无回路连通图。对于一个带权的无向连通图,其每个生成树所有边上的权值之和可能不同,我们把所有边上权值之和最小的生成树称为图的最小生成树。求图的最小生成树有很多实际应用。例如,通讯线路铺设造价最优问题就是一个最小生成树问题。

常见的求最小生成树的方法有两种:克鲁斯卡尔(Kruskal)算法和普里姆(Prim)算法。

2.普里姆(Prim)算法

1) 算法的基本思想:

普里姆算法的基本思想:普里姆算法是另一种构造最小生成树的算法,它是按逐个将顶点连通的方式来构造最小生成树的。

从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把该边加入到生成树的边集TE中,把它的顶点加入到集合U中。如此重复执行,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

假设G=(V,E)是一个具有n个顶点的带权无向连通图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则构造G的最小生成树T的步骤如下:

(1)初始状态,TE为空,U={v0},v0∈V;

(2)在所有u∈U,v∈V-U的边(u,v) ∈E中找一条代价最小的边(u′,v′)并入TE,同时将v′并入U;

重复执行步骤(2)n-1次,直到U=V为止。

在普里姆算法中,为了便于在集合U和(V-U)之间选取权值最小的边,需要设置两个辅助数组closest和lowcost,分别用于存放顶点的序号和边的权值。

对于每一个顶点v∈V-U,closest[v]为U中距离v最近的一个邻接点,即边 (v,closest[v]) 是在所有与顶点v相邻、且其另一顶点j∈U的边中具有最小权值的边,其最小权值为lowcost[v],即lowcost[v]=cost[v][closest[v]],采用邻接表作为存储结构:

设置一个辅助数组closedge[]:

lowcost域 存放生成树顶点集合内顶点到生成树外各顶点的各边上的当前最小权值;

adjvex域 记录生成树顶点集合外各顶点距离集合内哪个顶点最近(即权值最小)。

应用Prim算法构造最小生成树的过程:



[code]#Prim.py
#王渊
#2015.12.16
#Email:wyxidian@gmail.com

from pylab import *
from mpl_toolkits.mplot3d import Axes3D

#Display the Chinese word
rcParams['font.sans-serif'] = ['SimHei']
rcParams['axes.unicode_minus'] = False

INFINITY = 65535                        #代表无穷大
vexs = array([[0,10,INFINITY,INFINITY,INFINITY,11,INFINITY,INFINITY,INFINITY],#邻接矩阵
        [10,0,18,INFINITY,INFINITY,INFINITY,16,INFINITY,12],
        [INFINITY,INFINITY,0,22,INFINITY,INFINITY,INFINITY,INFINITY,8],
        [INFINITY,INFINITY,22,0,20,INFINITY,INFINITY,16,21],
        [INFINITY,INFINITY,INFINITY,20,0,26,INFINITY,7,INFINITY],
        [11,INFINITY,INFINITY,INFINITY,26,0,17,INFINITY,INFINITY],
        [INFINITY,16,INFINITY,INFINITY,INFINITY,17,0,19,INFINITY],
        [INFINITY,INFINITY,INFINITY,16,7,INFINITY,19,0,INFINITY],
        [INFINITY,12,8,21,INFINITY,INFINITY,INFINITY,INFINITY,0]])

lengthVex = len(vexs)                   #邻接矩阵大小
adjvex = zeros(lengthVex)               #连通分量,初始只有第一个顶点,当全部元素为1后,说明连通分量已经包含所有顶点
adjvex[0] = 1;
lowCost = vexs[0,:]                     #记录与连通分量连接的顶点的最小权值,初始化为与第一个顶点连接的顶点权值
lowCost[0] = 0
count = 0
while (count<9):
    I = (argsort(lowCost))[count]
    print("Vertex   [",count,"]:",I)
    adjvex[I] = lowCost[I]
    print("Edge [",count,"]:",adjvex[I])
    lowCost[I] = 0
    lowCost = array(list(map(lambda x,y:x if x<y else y,lowCost,vexs[I,:])))
    count = count+1
print("The length of the minimum cost spanning tree is: ", sum(adjvex))


运行结果:

Vertex代表依次加入最小生成树的各顶点,Edge代表依次加入最小生成树的各条边,最后给出最小生成树的总的长度。

[code]Vertex  [ 0 ]: 0
Edge    [ 0 ]: 0.0
Vertex  [ 1 ]: 1
Edge    [ 1 ]: 10.0
Vertex  [ 2 ]: 5
Edge    [ 2 ]: 11.0
Vertex  [ 3 ]: 8
Edge    [ 3 ]: 12.0
Vertex  [ 4 ]: 2
Edge    [ 4 ]: 8.0
Vertex  [ 5 ]: 6
Edge    [ 5 ]: 16.0
Vertex  [ 6 ]: 7
Edge    [ 6 ]: 19.0
Vertex  [ 7 ]: 4
Edge    [ 7 ]: 7.0
Vertex  [ 8 ]: 3
Edge    [ 8 ]: 16.0
The length of the minimum cost spanning tree is:  99.0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: