700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 图论基础知识--最小生成树算法kruskal(克鲁斯克尔)和普里姆算法(Prim算法);最短路径

图论基础知识--最小生成树算法kruskal(克鲁斯克尔)和普里姆算法(Prim算法);最短路径

时间:2022-01-26 18:35:05

相关推荐

图论基础知识--最小生成树算法kruskal(克鲁斯克尔)和普里姆算法(Prim算法);最短路径

一.基础知识

有向图 无向图

以无向图为例:

邻接矩阵:

度矩阵(对角矩阵):

二.最小生成树

应用:将网络顶点看着城市,边看着城市之间通讯网,边的权重看着成本,根据最小生成树可以构建城市之间成本最低的通讯网.

1.kruskal(克鲁斯克尔)算法

2.普里姆算法(Prim算法)

求点与点之间的最小生成树

代码:

#coding:utf-8"""最小生成树"""import networkx as nximport matplotlib.pyplot as pltimport numpy as npfrom numpy import randomG = nx.Graph()# Matrix = np.array(random.randint((5), size=(5, 5)))# print('==Matrix:', Matrix)# print(maps)Matrix = np.array( [[3, 4, 0, 2, 2],[4, 1, 0, 3, 4],[0, 0, 0, 4, 4],[2, 3, 4, 0, 3],[2, 4, 4, 3, 1]])#实际在用的时候,只用了下三角矩阵#构建无向图for i in range(len(Matrix)):for j in range(len(Matrix)):if Matrix[i, j] != 0:G.add_edge(i, j)nx.draw_networkx(G)plt.title("G")plt.show()class Graph(object):def __init__(self, Matrix):self.Matrix = Matrixself.nodenum = self.get_nodenum()self.edgenum = self.get_edgenum()def get_nodenum(self):return len(self.Matrix)def get_edgenum(self):count = 0for i in range(self.nodenum): # 获取除去对角的下三角矩阵for j in range(i):# print('i,j', i, j)if self.Matrix[i][j] > 0 and self.Matrix[i][j] < 9999:count += 1return countdef kruskal(self):list = []if self.nodenum <= 0 or self.edgenum < self.nodenum - 1:return listedge_list = []for i in range(self.nodenum): # 获取除去对角的下三角矩阵for j in range(i):if self.Matrix[i][j] < 9999:edge_list.append([i, j, self.Matrix[i][j]])print('==排序之前边的集合 edge_list:', edge_list)edge_list.sort(key=lambda a: a[2]) # 已经排好序的边集合print('==排序以后边的集合 edge_list:', edge_list)group = [[i] for i in range(self.nodenum)] # 存储代表元列表print('存储代表元列表', group)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:# 合并联通分量进行存储元列表更新list.append(edge)print('开始节点m,终止节点n:', m, n)group[m] = group[m] + group[n]group[n] = []print('==更新后的代表元列表:', group)return listdef prim(self):list = []if self.nodenum <= 0 or self.edgenum < self.nodenum - 1:return listselected_node = [0]candidate_node = [i for i in range(1, self.nodenum)]#候选节点# print('==candidate_node:', candidate_node)while len(candidate_node) > 0:begin, end, minweight = 0, 0, 9999for i in selected_node:for j in candidate_node:if self.Matrix[i][j] < minweight:minweight = self.Matrix[i][j]begin = i#存储开始节点end = j#存储终止节点list.append([begin, end, minweight])selected_node.append(end)#找到权重最小的边加入可选节点candidate_node.remove(end)#候选节点被找到进行移除return list##G = Graph(Matrix)print('邻接矩阵为\n%s' % G.Matrix)print('节点数据为%d,边数为%d\n' % (G.nodenum, G.edgenum))print('------最小生成树kruskal算法------')print(G.kruskal())print('------最小生成树prim算法')print(G.prim())

三.最短路径:

1.Dijkstra(迪杰斯特拉)算法

Dijkstra算法用于解决单源最短路问题,所谓单源最短路就是指定一个起点,求出这个起点到其它所有点的最短路。本质就是依次让每个顶点作为起点,更新最短路的过程。

示例:求M到各个顶点的最短路径

先构建邻接矩阵Adjacent, 初始状态dist[1~n] = inf, dist[M]=0,顶点更新状态vst[1~n] = 0

以点M为起点:

dist[M] = 0 vst[M] = 0dist[W] = inf vst[W] = 0dist[E] = inf vst[E] = 0dist[D] = inf vst[D] = 0dist[X] = inf vst[X] = 0

找出dist中值最小且未被使用的点,发现dist[M]=0最小,且vst[M]=0,未被使用,故将M作为新的起点.

找出所有M可达的顶点,为X、W、E

dist[X]=inf > 0+10 ,更新dist[X]=10

dist[W]=inf > 0+5 ,更新dist[W]=5

dist[E]=inf > 0+8 ,更新dist[E]=8

M已被使用,vst[M]=1

dist[M] = 0 vst[M] = 1dist[W] = 5 vst[W] = 0dist[E] = 8 vst[E] = 0dist[D] = inf vst[D] = 0dist[X] = 10 vst[X] = 0

依次遍历每个顶点........

Inf = float('inf')# Dijkstra算法,就是依次让每个顶点作为起点,更新最短路的过程。Adjacent = [[0, 10, 5, Inf, 8],[10, 0, 3, 1, Inf],[5, 3, 0, 9, 2],[Inf, 1, 9, 0, 6],[8, Inf, 2, 6, 0]]Src, Dst, N = 0, 4, 5def dijstra(adj, src, dst, n):dist = [Inf] * n # 初始化为inf无穷大dist[src] = 0 # 起始点到起始点距离为0vst = [0] * n # 记录已经确定的顶点prev = [0] * nwhile True:now = -1for u in range(n): # 找到dist最小且vst=0的点作为起点if not vst[u] and (now == -1 or dist[u] < dist[now]):now = uprint('====now:', now)if now == -1: # now未被更新,即表示所有顶点都被使用过,算法结束breakfor v in range(n): # 遍历当前起点now能到达的所有点if dist[v] > dist[now] + adj[now][v]: # 如果dist[v]大于dist[now] + adj[now][v] 则更新dist[v] = dist[now] + adj[now][v]prev[v] = nowprint('==dist:', dist)# assert 1==0vst[now] = 1 # 当前起点now已被使用过,vst[now]=1# print('===dist:', dist)# print('==prev:', prev)## print('==dist[dst]:', dist[dst])return dist, prevdist, prev = dijstra(Adjacent, Src, Dst, N)print('==dist,prev:', dist, prev)def construct_path(prev, index, path=[]):path = path + [prev[index]]if prev[index] == 0:#终止条件return pathnew_path = construct_path(prev, prev[index], path)return new_path# res = construct_path(prev, 4,[4])# print('==res:', res)for i in range(len(prev)):path = construct_path(prev, i, [i])print('{}节点路径为:{}'.format(i, path))

2.Floyd(弗洛伊德)

本质任意两个节点最短路径是否经过此节点,用dp的思想来存储中间结果.

示例:

#Floyd(弗洛伊德)找最短路径 本质任意两个节点最短路径是否经过此节点import numpy as npInf = float('inf')DIS = [[0, 3, 8, Inf, -4],[Inf, 0, Inf, 1, 7],[Inf, 4, 0, Inf, Inf],[2, Inf, -5, 0, Inf],[Inf, Inf, Inf, 6, 0]]Direction = [[0, 1, 2, 3, 4],[0, 1, 2, 3, 4],[0, 1, 2, 3, 4],[0, 1, 2, 3, 4],[0, 1, 2, 3, 4]]V = 5#k就是是否要经过的节点,i就是开始节点,j就是终止节点for k in range(V):for i in range(V):for j in range(V):if DIS[i][k] + DIS[k][j] < DIS[i][j]:DIS[i][j] = DIS[i][k] + DIS[k][j]Direction[i][j] = Direction[i][k]print('最终的距离矩阵{}'.format(np.array(DIS)))print('方向矩阵{}'.format(np.array(Direction)))def construct_path(Direction, i, j, path=[]):path = path + [Direction[i][j]]if Direction[i][j] == j:#终止条件return pathnew_path = construct_path(Direction, Direction[i][j], j, path)return new_path#找到路径for i in range(V):for j in range(V):path = construct_path(Direction, i, j, [i])print('{}--{}节点路径为:{}'.format(i, j, path))

最终的距离矩阵和方向矩阵,其中方向矩阵可以用来还原开始节点到终止节点的路径:

参考:

/weixin_43093481/article/details/82702176

/video/BV1q4411M7r9?from=search&seid=4042347737055062965

图论基础知识--最小生成树算法kruskal(克鲁斯克尔)和普里姆算法(Prim算法);最短路径算法Dijkstra(迪杰斯特拉)和Floyd(弗洛伊德)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。