最小生成树------克鲁斯卡尔(Kruskal)算法
1、基本介绍
它是一种将无向权重图构造成最小生成树(指的是树权重sum最小)的一种算法,基本思路是:
首先将图中的边按照权重升序排列得到一组有序数列[ [ i,j,w],…, [ ] ],例如以上就是按照w的升序排列得到的图G(V,E)的边列表,其中i,j分别代表这条边所连接的两个node节点,w表示这条边的权重值。
设待完成的生成树表示为T(U,TE)
之后利用循环迭代各条边[ i,j,w],如果这条边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时将两个不同连通分量合并为一个连通分量;如果这条边的两个顶点属于同一个连通分量,则舍去此边,避免形成回路。
Note: 图G有N个节点,那么生成树有且仅有N-1条边
2、举个栗子
得到的边列表(edge_list):[ [1,4,3], [4,5,4], [0,5,5], [2,3,6], [0,1,7], [3,4,8], [1,2,9], [3,5,10] ]
最后那张图v3-v5之间的连线不存在
对于连通分量的合并,通过以上例子可以这样理解
开始,因为有6个节点,所以生成6个组group,分别是groups=[v0,v1,v2,v3,v4,v5] (之后用[[0],[1],[2],[3],[4],[5]]代替)
第一条边为[1,4,3],节点1和节点4在groups中分别处于group=[1]和group=[4]所以可以加入生成树中,然后将这两个group合并(也就是之前所说的合并两个连通分量),这样groups = [[0],[1,4],[2],[3],[],[5]]
可以看到groups的中会出现一个空的连通分量。
同理依次类推,当其中一条边的两个顶点处于同一个group中,那么就会出现回路,我们应该避免这种情况。
# python 代码
// An highlighted block
//input : edge_list : [ [1,4,3], [4,5,4], [0,5,5], [2,3,6], [0,1,7], [3,4,8], [1,2,9], [3,5,10] ]
// nodenum : 6
//output : [ [1,4,3], [4,5,4], [0,5,5], [2,3,6], [3,4,8]]
def kruskal(edge_list,nodenum):
# input : 排序好的边列表and节点个数
# output : 最小生成树的边列表
res = []
group = [[i] for i in range(nodenum)]
for edge in edge_list:
for i in range(len(group)):
if edge[0] in group[i]:
m = i
if edge[1] in group[i]:
n = i
if m != n:
res.append(edge)
group[m] = group[m] +group[n]
group[n] = []
return res