最小生成树
一个连通图的生成树是一个极小的连通子图,包含有图中全部的顶点,但只有足以构成一棵树的n-1条边。我们把构造连通网的最小代价生成树称为最小生成树 ( M i n i m u m C o s t S p a n n i n g T r e e ) (Minimum Cost Spanning Tree) (MinimumCostSpanningTree)。
Prim算法
普里姆
(
P
r
i
m
)
( Prim )
(Prim)算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的。
算法思想:假设
N
=
(
V
,
{
E
}
)
N=( V,\{E\} )
N=(V,{E})是连通网,
T
E
TE
TE是
N
N
N上最小生成树中边的集合。算法从
U
=
{
u
0
}
U =\{u_0\}%( u_0\in P)
U={u0},
T
E
=
{
}
TE=\{\}
TE={}开始。重复执行下述操作:在所有
u
∈
U
,
v
∈
V
−
U
u\in U,v\in V- U
u∈U,v∈V−U的边
(
u
,
v
)
∈
E
(u,v)\in E
(u,v)∈E中找一条代价最小的边
(
u
0
,
v
0
)
(u_0,v_0)
(u0,v0)并入集合
T
E
TE
TE,同时
v
0
v_0
v0并入
U
U
U,直至
U
=
V
U=V
U=V为止。此时
T
E
TE
TE中必有
n
−
1
n-1
n−1条边,则
T
=
(
V
,
T
E
)
T= (V,{TE})
T=(V,TE)为
N
N
N的最小生成树。
Prim代码
这里我们只需要网 G G G的顶点与边的列表即可
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 09:18:08 2019
@author: Administrator
"""
from numpy import *
def Prim(G):
V=G.vertices #例V=['A','B','C',...]
E=G.edges_list[:] #例E=[['A','B',weight],...]
V_new=[V[0]]
E_new=[]
a=[None,None] #a储存找到的点与边
i=1 #用于防止死循环
while(set(V_new)!=set(V)):
MIN=inf
for edge in E: #对E循环,找到符合要求的最小权的边
if edge[0] in V_new and edge[1] not in V_new:
if edge[2]<MIN:
a[0]=edge[1]
a[1]=edge
MIN=edge[2]
elif edge[1] in V_new and edge[0] not in V_new:
if edge[2]<MIN:
a[0]=edge[0]
a[1]=edge
MIN=edge[2]
if a[0]:
V_new.append(a[0])
E_new.append(a[1])
E.remove(a[1]) #将找到的最小权的边移除E
i+=1
if i>10000:break
return V_new,E_new
Kruskal算法
克鲁斯卡尔
(
K
r
u
s
k
a
l
)
(Kruskal)
(Kruskal)算法是先将边按照其权的大小排序,从最小权的边起,依次将不足以构成环的边加入最小生成树中。
算法思想:假设
N
=
(
V
,
{
E
}
)
N=(V,\{E\})
N=(V,{E})是连通网,则令最小生成树的初始状态为只有
n
n
n个顶点而无边的非连通图
T
=
{
V
,
{
}
}
T=\{V,\{\}\}
T={V,{}},图中每个顶点自成一个连通分量。在
E
E
E中选择代价最小的边,若该边依附的顶点落在
T
T
T中不同的连通分量上,则将此边加入到
T
T
T中,否则舍去此边而选择下一条代价最小的边。依次类推,直至
T
T
T中所有顶点都在同一连通分量上为止。
Kruskal代码
同样,这里我们也只需要网 G G G的顶点与边的列表即可
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 10:45:38 2019
@author: Administrator
"""
def Kruskal(G):
vertices=G.vertices
#例V=['A','B','C',...]
edges=sorted(G.edges_list,key=lambda x:x[2])
#例G.edges_list=[['A','B',weight1],...],再将之按权的大小排序,赋值给edges
Edges=[]
connected=[]
for V in vertices:
connected.append([V])
for E in edges:
for j in range(len(connected)):
if E[0] in connected[j]:
m=j
if E[1] in connected[j]:
n=j
if m!=n: #若E[0]与E[1]所属的连通分量不同
connected[m]=connected[m]+connected[n] #将第m个连通分量与第n个连通分量合并于m处
del connected[n] #删去第n个连通分量
Edges.append(E)
return Edges