最小生成树算法

一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决。

Prim算法

理解

Prim算法从单一顶点开始,其按照以下步骤逐步扩大树中所包含顶点的数目,直到遍及连通图的所有顶点。

  1. 输入:一个加权连通图,其中顶点集合为V,边集合为E;
  2. 初始化:Vn = {x},其中x为集合V中的任一节点(起始点),Enew = {};
  3. 重复下列操作,直到Vn = V:
    1. 在集合E中选取权值最小的边(u, v),其中u为集合Vn中的元素,而v则是V中没有加入Vn的顶点(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
    2. 将v加入集合Vn中,将(u, v)加入集合En中;
  4. 输出:使用集合Vn和En来描述所得到的最小生成树。

以下面这张图作为例子,表格中的Vertex、Kown、Cost、Path分别表示顶点信息、是否访问过,权值,到达路径;

我们随机的选择顶点0作为起点,其执行步骤为:

步骤 选中结点
顶点0作为起始点 0
根据(6, 7, 8)的方案选中6 1
根据顶点1能够到达的权值(7, 4, 3)和顶点0能够到达的权值(7, 8)中选择3 5
根据顶点5能够到达的权值(8)和根据顶点1能够到达的权值(7, 4)和顶点0能够到达的权值(7, 8)中选择4 6
根据顶点6能够到达的权值(6, 7)和顶点0能够到达的权值(7)中选择6 2
根据顶点0能够到达的权值(7)和顶点6能够到达的权值(7)中选择7 4
根据顶点6能够到达的权值(7)选择7 7
根据顶点7能够到达的权值(2)选择2 3
全部结点都访问过,退出

最终得到下面的结果,其中Path中的-1表示其作为起始点;

实现

根据前面的那幅图来实现,如下:

class MST(object):
def __init__(self, graph):
self.graph = graph
self.N = len(self.graph)
pass
def prim(self, start):
index = start
cost, path = [0] * self.N, [0] * self.N
# 初始化起点
known = [x for x in map(lambda x: True if x == start else False, [x for x in range(self.N)])]
path[start] = -1
for i in range(self.N):
cost[i] = self.graph[start][i]
# 遍历其余各个结点
for i in range(1, self.N):
mi = 1e9
# 找出相对最小权重的结点
for j in range(self.N):
if not known[j] and mi > cost[j]:
mi, index = cost[j], j
# 计算路径值
for j in range(self.N):
if self.graph[j][index] == mi:
path[index] = j
known[index] = True
# 更新index连通其它结点的权重
for j in range(self.N):
if not known[j] and cost[j] > self.graph[index][j]:
cost[j] = self.graph[index][j]
print(path)
# 图用临接矩阵表示
MST([
[1e9, 6, 8, 1e9, 7, 1e9, 1e9, 1e9],
[6, 1e9, 7, 1e9, 1e9, 3, 4, 1e9],
[8, 7, 1e9, 1e9, 1e9, 1e9, 6, 1e9],
[1e9, 1e9, 1e9, 1e9, 1e9, 1e9, 1e9, 2],
[7, 1e9, 1e9, 1e9, 1e9, 1e9, 1e9, 1e9],
[1e9, 3, 1e9, 1e9, 1e9, 1e9, 1e9, 9],
[1e9, 4, 6, 1e9, 1e9, 1e9, 1e9, 7],
[1e9, 1e9, 1e9, 2, 1e9, 9, 7, 1e9],
]).prim(0)

path结果为:[-1, 0, 6, 7, 0, 1, 1, 6]

Kruskal算法

理解

构造一个只含n个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树的根节点,则它是一个含有n棵树的森林 。之后,从图的边集中选取一条权值最小的边,若该边的两个顶点分属不同的树 ,则将其加入子图,也就是这两个顶点分别所在的 两棵树合成一棵树;反之,若该边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林只有一棵树。kruskal算法能够在并查集的基础很快的实现。

以下面这张图作为例子,其中左边的表格是一个并查集,表示可以连通的结点。我们首先要根据权值对每条边进行排序,接着开始处理每一条边的情况。

最终得到下面的结果图:

实现

因为我们要处理边,所以需要建立边的数据结构,并且要从给定的图中获取每一条边的数据

class Edge(object):
def __init__(self, start, end, weight):
self.start = start
self.end = end
self.weight = weight
def getEdges(self):
edges = []
for i in range(self.vertex):
for j in range(i+1, self.vertex):
if self.graph[i][j] != 1e9:
edge = Edge(i, j, self.graph[i][j])
edges.append(edge)
return edges

接下来就是kruskal函数:

    def kruskal(self):
union = dict.fromkeys([i for i in range(self.vertex)], -1) # 辅助数组,判断两个结点是否连通
self.edges = self.getEdges()
self.edges.sort(key=lambda x: x.weight)
res = []
def getend(start):
while union[start] >= 0:
start = union[start]
return start
for edge in self.edges:
# 找到连通线路的最后一个结点
n1 = getend(edge.start)
n2 = getend(edge.end)
# 如果为共同的终点则不处理
if n1 != n2:
print('{}----->{}'.format(n1, n2))
(n1, n2) = (n2, n1) if union[n1] < union[n2] else (n1, n2)
union[n2] += union[n1]
union[n1] = n2
res.append(edge)
print(union.values())

其中union打印出来的结果和图中是一致的,为[3, 3, 5, 6, 6, 6, -8, 3]

最小生成树之Prim算法和Kruskal算法的更多相关文章

  1. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

  2. 【数据结构】最小生成树之prim算法和kruskal算法

    在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...

  3. 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

    最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...

  4. 最小生成树(prim算法和kruskal算法)

    学习博客:https://www.cnblogs.com/zhangming-blog/p/5414514.html 其实就是加点法:从不属于这个集合的点中找从本集合可以找到的最小边,加入本集合 看代 ...

  5. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  6. 最小生成树——Prim算法和Kruskal算法

    洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...

  7. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  8. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  9. Prim算法和Kruskal算法的正确性证明

    今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...

随机推荐

  1. OpenGL教程(0)——介绍

    OpenGL介绍 OpenGL,全称Open Graphics Library,是一个用C语言写的图形API.通俗地说,OpenGL用来绘制2D/3D图形.目前OpenGL的运用十分广泛,有许多用Op ...

  2. 学习笔记TF019:序列分类、IMDB影评分类

    序列分类,预测整个输入序列的类别标签.情绪分析,预测用户撰写文字话题态度.预测选举结果或产品.电影评分. 国际电影数据库(International Movie Database)影评数据集.目标值二 ...

  3. 2-SAT算法

    参考blog 参考论文 参考论文 题目 & 题解 裸2-SAT poj3683 poj3207 poj3678 poj3648 2-SAT + 二分法 poj2723 poj2749 hdu3 ...

  4. Java常用类之【八种基本数据类型】

    一.装箱和拆箱 装箱:将基本数据类型包装为对应的包装类对象 拆箱:将包装类对象转换成对应的基本数据类型 JDK5.0中为基本数据类型提供了自动装箱(boxing).拆箱(unboxing)功能 二.八 ...

  5. 38. Count and Say - Unsolved

    https://leetcode.com/problems/count-and-say/#/description The count-and-say sequence is the sequence ...

  6. 主存与Cache的地址映射

    最近在复习计算机体系结构,选用的教材是名闻遐迩的<计算机体系结构 量化研究方法 第五版>(Computer Architecture A Quantitative Approach), 关 ...

  7. 关于cas server无法通过session持久化方式实现集群的问题

    最近在搭建cas单点登录系统 ,在建立集群时发生一个问题. 搭建的环境是tomcat+tomcat-redis-session-manager+redis+cas 在对tomcat的session进行 ...

  8. (转)微信禁用右上角的分享按钮,WeixinJSBridge API以及隐藏分享的子按钮等菜单项

    <!--禁用微信分享按钮--> <script> function onBridgeReady() { WeixinJSBridge.call('hideOptionMenu' ...

  9. [BZOJ4008]亚瑟王

    Description 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑. 他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂 亮.众所周知,亚瑟王是一 ...

  10. angular.js添加自定义服务依赖项方法

    <!DOCTYPE html> <html lang="en" ng-app="myapp"> <head> <met ...