NetworkX系列教程(10)-算法之一:最短路径问题
重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图论中常用算法弄个明白在写这部分.
图论常用算法看我的博客:
下面我将使用NetworkX实现上面的算法,建议不清楚的部分打开两篇博客对照理解.
我将图论的经典问题及常用算法的总结写在下面两篇博客中:
图论---问题篇
图论---算法篇
目录:
注意:如果代码出现找不库,请返回第一个教程,把库文件导入.
11.Graph相关算法
11.1最短路径
11.1.1无向图和有向图
- #定义并画出该图
- G = nx.path_graph(5)
- nx.add_path(G,[0,5,2])
- nx.add_path(G,[0,6,4])
- nx.draw(G,with_labels=True)
- plt.title('无向图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- #计算最短路径
- print('0节点到4节点最短路径: ',nx.shortest_path(G, source=0, target=4))
- p1 = nx.shortest_path(G, source=0)
- print('0节点到所有节点最短路径: ',p1)
- #计算图中所有的最短路径
- print('计算图中节点0到节点2的所有最短路径: ',[p for p in nx.all_shortest_paths(G, source=0, target=2)])
- #计算最短路径长度
- p2=nx.shortest_path_length(G, source=0, target=2) #最短路径长度
- p3=nx.average_shortest_path_length(G) #计算平均最短路径长度
- print('节点0到节点2的最短路径长度:',p2,' 平均最短路径长度: ',p3)
- #检测是否有路径
- print('检测节点0到节点2是否有路径',nx.has_path(G,0,2))

输出:
- 0节点到4节点最短路径: [0, 6, 4]
- 0节点到所有节点最短路径: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 6, 4], 5: [0, 5], 6: [0, 6]}
- 计算图中节点0到节点2的所有最短路径: [[0, 1, 2], [0, 5, 2]]
- 节点0到节点2的最短路径长度: 2 平均最短路径长度: 1.8095238095238095
- 检测节点0到节点2是否有路径 True
11.1.2无权图
- G = nx.path_graph(3)
- nx.draw(G,with_labels=True)
- plt.title('无权图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- path1 = nx.single_source_shortest_path(G, 0) #计算当前源与所有可达节点的最短路径
- length1 = nx.single_source_shortest_path_length(G, 0) #计算当前源与所有可达节点的最短路径的长度
- path2 = dict(nx.all_pairs_shortest_path(G)) #计算graph两两节点之间的最短路径
- length2 = dict(nx.all_pairs_shortest_path_length(G)) #计算graph两两节点之间的最短路径的长度
- prede1=nx.predecessor(G, 0) #返回G中从源到所有节点最短路径的前驱
- print('当前源与所有可达节点的最短路径: ',path1,'\n当前源与所有可达节点的最短路径的长度: ',length1)
- print('\ngraph两两节点之间的最短路径: ',path2,'\ngraph两两节点之间的最短路径的长度: ',length2)
- print('\nG中从源到所有节点最短路径的前驱: ',prede1)

输出:
- 当前源与所有可达节点的最短路径: {0: [0], 1: [0, 1], 2: [0, 1, 2]}
- 当前源与所有可达节点的最短路径的长度: {0: 0, 1: 1, 2: 2}
- graph两两节点之间的最短路径: {0: {0: [0], 1: [0, 1], 2: [0, 1, 2]}, 1: {0: [1, 0], 1: [1], 2: [1, 2]}, 2: {0: [2, 1, 0], 1: [2, 1], 2: [2]}}
- graph两两节点之间的最短路径的长度: {0: {0: 0, 1: 1, 2: 2}, 1: {0: 1, 1: 0, 2: 1}, 2: {0: 2, 1: 1, 2: 0}}
- G中从源到所有节点最短路径的前驱: {0: [], 1: [0], 2: [1]}
11.1.3有权图(迪杰斯特拉)
- G = nx.path_graph(5, create_using = nx.DiGraph())
- nx.draw(G,with_labels=True)
- plt.title('有向图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- #计算加权图最短路径长度和前驱
- pred, dist = nx.dijkstra_predecessor_and_distance(G, 0)
- print('\n加权图最短路径长度和前驱: ',pred, dist)
- #返回G中从源到目标的最短加权路径,要求边权重必须为数值
- print('\nG中从源0到目标4的最短加权路径: ',nx.dijkstra_path(G,0,4))
- print('\nG中从源0到目标4的最短加权路径的长度: ',nx.dijkstra_path_length(G,0,4)) #最短路径长度
- #单源节点最短加权路径和长度。
- length1, path1 = nx.single_source_dijkstra(G, 0)
- print('\n单源节点最短加权路径和长度: ',length1, path1)
- #下面两条和是前面的分解
- # path2=nx.single_source_dijkstra_path(G,0)
- # length2 = nx.single_source_dijkstra_path_length(G, 0)
- #print(length1,'$', path1,'$',length2,'$',path2)
- #多源节点最短加权路径和长度。
- path1 = nx.multi_source_dijkstra_path(G, {0, 4})
- length1 = nx.multi_source_dijkstra_path_length(G, {0, 4})
- print('\n多源节点最短加权路径和长度:', path1,length1)
- #两两节点之间最短加权路径和长度。
- path1 = dict(nx.all_pairs_dijkstra_path(G))
- length1 = dict(nx.all_pairs_dijkstra_path_length(G))
- print('\n两两节点之间最短加权路径和长度: ',path1,length1)
- #双向搜索的迪杰斯特拉
- length, path = nx.bidirectional_dijkstra(G, 0, 4)
- print('\n双向搜索的迪杰斯特拉:',length, path)

输出:
- 加权图最短路径长度和前驱: {0: [], 1: [0], 2: [1], 3: [2], 4: [3]} {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
- G中从源0到目标4的最短加权路径: [0, 1, 2, 3, 4]
- G中从源0到目标4的最短加权路径的长度: 4
- 单源节点最短加权路径和长度: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4} {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}
- 多源节点最短加权路径和长度: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [4]} {0: 0, 1: 1, 2: 2, 3: 3, 4: 0}
- 两两节点之间最短加权路径和长度: {0: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}, 1: {1: [1], 2: [1, 2], 3: [1, 2, 3], 4: [1, 2, 3, 4]}, 2: {2: [2], 3: [2, 3], 4: [2, 3, 4]}, 3: {3: [3], 4: [3, 4]}, 4: {4: [4]}} {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, 1: {1: 0, 2:1, 3: 2, 4: 3}, 2: {2: 0, 3: 1, 4: 2}, 3: {3: 0, 4: 1}, 4: {4: 0}}
- 双向搜索的迪杰斯特拉: 4 [0, 1, 2, 3, 4]
11.1.4贝尔曼-福特(Bellman-Ford)算法
- G = nx.path_graph(5, create_using = nx.DiGraph())
- nx.draw(G,with_labels=True)
- plt.title('有权图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- print('G中从源到目标的最短加权路径: ',nx.bellman_ford_path(G, 0, 4))
- print('\nG中从源到目标的最短加权路径的长度:',nx.bellman_ford_path_length(G,0,4))
- path1=nx.single_source_bellman_ford_path(G,0)
- length1 = dict(nx.single_source_bellman_ford_path_length(G, 0))
- print('\n单源节点最短加权路径和长度: ',path1,'\n单源节点最短加权路径和长度: ',length1)
- path2 = dict(nx.all_pairs_bellman_ford_path(G))
- length2 = dict(nx.all_pairs_bellman_ford_path_length(G))
- print('\n两两节点之间最短加权路径和长度: ',path2,length2)
- length, path = nx.single_source_bellman_ford(G, 0)
- pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0)
- print('\n加权图最短路径长度和前驱: ',pred,dist)

输出:
- G中从源到目标的最短加权路径: [0, 1, 2, 3, 4]
- G中从源到目标的最短加权路径的长度: 4
- 单源节点最短加权路径和长度: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}
- 单源节点最短加权路径和长度: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
- 两两节点之间最短加权路径和长度: {0: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}, 1: {1: [1], 2: [1, 2], 3: [1, 2, 3], 4:
[1, 2, 3, 4]}, 2: {2: [2], 3: [2, 3], 4: [2, 3, 4]}, 3: {3: [3], 4:
[3, 4]}, 4: {4: [4]}} {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, 1: {1: 0, 2:
1, 3: 2, 4: 3}, 2: {2: 0, 3: 1, 4: 2}, 3: {3: 0, 4: 1}, 4: {4: 0}}
加权图最短路径长度和前驱: {0: [None], 1: [0], 2: [1], 3: [2], 4: [3]} {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
11.1.5检测负权重边
- #定义并画出该图
- G = nx.cycle_graph(5, create_using = nx.DiGraph())
- #添加负权重边前后
- print(nx.negative_edge_cycle(G))
- G[1][2]['weight'] = -7
- print(nx.negative_edge_cycle(G))
输出:
- False
- True
11.1.6使用约翰逊(Johnson)的算法
- #生成graph
- G = nx.DiGraph()
- G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5),('0', '2', 2), ('1', '2', 4), ('2', '3', 1)])
- #边和节点信息
- edge_labels = nx.get_edge_attributes(G,'weight')
- labels={'0':'0','1':'1','2':'2','3':'3'}
- #生成节点位置
- pos=nx.spring_layout(G)
- #把节点画出来
- nx.draw_networkx_nodes(G,pos,node_color='g',node_size=500,alpha=0.8)
- #把边画出来
- nx.draw_networkx_edges(G,pos,width=1.0,alpha=0.5,edge_color='b')
- #把节点的标签画出来
- nx.draw_networkx_labels(G,pos,labels,font_size=16)
- #把边权重画出来
- nx.draw_networkx_edge_labels(G, pos, edge_labels)
- #显示graph
- plt.title('有权图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- #使用johnson算法计算最短路径
- paths = nx.johnson(G, weight='weight')
- print(paths)

输出:
- {'2': {'2': ['2'], '3': ['2', '3']}, '3': {'3': ['3']}, '0': {'2': ['0', '1', '2'], '3': ['0', '1', '2', '3'], '0': ['0'], '1': ['0','1']}, '1': {'2': ['1', '2'], '3': ['1', '2', '3'], '1': ['1']}}
11.1.7弗洛伊德算法(Floyd-Warshall)
- #使用Floyd算法找到所有对最短路径长度。
- G = nx.DiGraph()
- G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5),('0', '2', 2), ('1', '2', 4), ('2', '3', 1)])
- #边和节点信息
- edge_labels = nx.get_edge_attributes(G,'weight')
- labels={'0':'0','1':'1','2':'2','3':'3'}
- #生成节点位置
- pos=nx.spring_layout(G)
- #把节点画出来
- nx.draw_networkx_nodes(G,pos,node_color='g',node_size=500,alpha=0.8)
- #把边画出来
- nx.draw_networkx_edges(G,pos,width=1.0,alpha=0.5,edge_color='b')
- #把节点的标签画出来
- nx.draw_networkx_labels(G,pos,labels,font_size=16)
- #把边权重画出来
- nx.draw_networkx_edge_labels(G, pos, edge_labels)
- #显示graph
- plt.title('有权图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- #计算最短路径长度
- lenght=nx.floyd_warshall(G, weight='weight')
- #计算最短路径上的前驱与路径长度
- predecessor,distance1=nx.floyd_warshall_predecessor_and_distance(G, weight='weight')
- #计算两两节点之间的最短距离,并以numpy矩阵形式返回
- distance2=nx.floyd_warshall_numpy(G, weight='weight')
- print(list(lenght))
- print(predecessor)
- print(list(distance1))
- print(distance2)

输出:
- ['2', '3', '0', '1']
- {'2': {'3': '2'}, '0': {'2': '1', '3': '2', '1': '0'}, '1': {'2': '1', '3': '2'}}
- ['2', '3', '0', '1']
- [[ 0. 1. inf inf]
- [inf 0. inf inf]
- [-1. 0. 0. -5.]
- [ 4. 5. inf 0.]]
注:输出中的矩阵不是按照节点0,1,2,3排序,而是2,1,3,0,即如图:

11.1.8A*算法
- G = nx.path_graph(5)
- #显示graph
- nx.draw(G,with_labels=True)
- plt.title('有x向图',fontproperties=myfont)
- plt.axis('on')
- plt.xticks([])
- plt.yticks([])
- plt.show()
- #直接输出路径和长度
- print(nx.astar_path(G, 0, 4))
- print(nx.astar_path_length(G, 0, 4))

输出:
- [0, 1, 2, 3, 4]
- 4
NetworkX系列教程(10)-算法之一:最短路径问题的更多相关文章
- NetworkX系列教程(10)-算法之五:广度优先与深度优先
小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...
- NetworkX系列教程(10)-算法之四:拓扑排序与最大流问题
小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...
- NetworkX系列教程(10)-算法之三:关键路径问题
小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...
- NetworkX系列教程(10)-算法之二:最小/大生成树问题
小书匠 Graph 图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定 ...
- NetworkX系列教程(9)-线性代数相关
小书匠 Graph 图论 学过线性代数的都了解矩阵,在矩阵上的文章可做的很多,什么特征矩阵,单位矩阵等.grpah存储可以使用矩阵,比如graph的邻接矩阵,权重矩阵等,这节主要是在等到graph后 ...
- NetworkX系列教程(2)-graph生成器
小书匠Graph图论 本节主要讲解如何快速使用内置的方法生成graph,官方的文档在这里,里面包含了networkX的所有graph生成器,下面的内容只是我节选的内容,并将graph画出来而已. 声明 ...
- NetworkX系列教程(1)-创建graph
小书匠Graph图论 研究中经常涉及到图论的相关知识,而且常常面对某些术语时,根本不知道在说什么.前不久接触了NetworkX这个graph处理工具,发现这个工具已经解决绝大部分的图论问题(也许只是我 ...
- HTML5游戏开发系列教程10(译)
原文地址:http://www.script-tutorials.com/html5-game-development-lesson-10/ 最后我们将继续使用canvas来进行HTML5游戏开发系列 ...
- Python Twisted系列教程10:增强defer功能的客户端
作者:dave@http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/ 译者:杨晓伟(采用意译) 可以从这 ...
随机推荐
- sass快速使用
sass的使用 建议使用一种语法格式(scss) scss sass转换 sass-convert main.scss main.sass sass变量声明 example: $headline-ff ...
- io.ByteIO和open操作二进制流的区别(转)
转自Stack Overflow:https://stackoverflow.com/questions/42800250/difference-between-open-and-io-bytesio ...
- hdu 2586 欧拉序+rmq 求lca
题意:求树上任意两点的距离 先说下欧拉序 对这颗树来说 欧拉序为 ABDBEGBACFHFCA 那欧拉序有啥用 这里先说第一个作用 求lca 对于一个欧拉序列,我们要求的两个点在欧拉序中的第一个位置之 ...
- 如何使用Class和ClassLoader加载文件
很多时候我们都需要在程序中加载各种文件,比如在加载配置文件,加载properties文件,或者只是加载一个文本文件,然后输出其中的内容,我在初学java的时候,就对加载文件非常头疼,今天又遇见了加载文 ...
- 2..net core 和.net framework 版本
同一台机器上可以安装多个版本的.net core runtime.比如: 每个.net core项目都可以指定自己所用的版本,所以改变某个项目的target version不会影响到其他的.安装新的r ...
- netcore使用EFcore(第一个实例)
说明:搭建netcore 使用efcore入门教程,跟着这个教程,傻瓜都可以成功!O(∩_∩)O哈哈~,咱们开始吧: 首先介绍下环境: vs2017, netcore2.2, EntityFramew ...
- raspbian buster阿里镜像
配置以前,谨记教诲,先去看一下是否有对应版本的源,如下所示,阿里这更新速度...确实挺赶潮流的 最后就是正常更新即可,这样就快多了,要不然用国外的源,还不知道要等到猴年马月的. sudo apt-ge ...
- MyBatis 常用词汇含义
JDBC:java Data Base Connection(Java与数据库连接): ORM:Object Relational Mapping(对象关系映射,简称ORM,或者O/RM,或者O/M ...
- 关于MQ的几件小事(五)如何保证消息按顺序执行
1.为什么要保证顺序 消息队列中的若干消息如果是对同一个数据进行操作,这些操作具有前后的关系,必须要按前后的顺序执行,否则就会造成数据异常.举例: 比如通过mysql binlog进行两个数据库的数据 ...
- ElementUI对话框(dialog)提取为子组件
需求:在页面的代码太多,想把弹窗代码提取为子组件,复用也方便. 这里涉及到弹窗el-dialog的一个属性show-close: show-close="false"是设置不显 ...