zoukankan      html  css  js  c++  java
  • NetworkX系列教程(10)-算法之一:最短路径问题

    重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图论中常用算法弄个明白在写这部分.

    图论常用算法看我的博客:

    下面我将使用NetworkX实现上面的算法,建议不清楚的部分打开两篇博客对照理解.
    我将图论的经典问题及常用算法的总结写在下面两篇博客中:
    图论---问题篇
    图论---算法篇

    目录:


    注意:如果代码出现找不库,请返回第一个教程,把库文件导入.

    11.Graph相关算法

    11.1最短路径

    11.1.1无向图和有向图

    1. #定义并画出该图 
    2. G = nx.path_graph(5) 
    3. nx.add_path(G,[0,5,2]) 
    4. nx.add_path(G,[0,6,4]) 
    5. nx.draw(G,with_labels=True) 
    6. plt.title('无向图',fontproperties=myfont) 
    7. plt.axis('on') 
    8. plt.xticks([]) 
    9. plt.yticks([]) 
    10. plt.show() 
    11.  
    12. #计算最短路径 
    13. print('0节点到4节点最短路径: ',nx.shortest_path(G, source=0, target=4)) 
    14. p1 = nx.shortest_path(G, source=0) 
    15. print('0节点到所有节点最短路径: ',p1) 
    16.  
    17. #计算图中所有的最短路径 
    18. print('计算图中节点0到节点2的所有最短路径: ',[p for p in nx.all_shortest_paths(G, source=0, target=2)]) 
    19.  
    20. #计算最短路径长度 
    21. p2=nx.shortest_path_length(G, source=0, target=2) #最短路径长度 
    22. p3=nx.average_shortest_path_length(G) #计算平均最短路径长度 
    23. print('节点0到节点2的最短路径长度:',p2,' 平均最短路径长度: ',p3) 
    24.  
    25. #检测是否有路径 
    26. print('检测节点0到节点2是否有路径',nx.has_path(G,0,2)) 

    无向图和有向图最短路径示例
    无向图和有向图最短路径示例

    输出:

    1. 0节点到4节点最短路径: [0, 6, 4] 
    2. 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]} 
    3. 计算图中节点0到节点2的所有最短路径: [[0, 1, 2], [0, 5, 2]] 
    4. 节点0到节点2的最短路径长度: 2 平均最短路径长度: 1.8095238095238095 
    5. 检测节点0到节点2是否有路径 True 

    11.1.2无权图

    1. G = nx.path_graph(3) 
    2. nx.draw(G,with_labels=True) 
    3. plt.title('无权图',fontproperties=myfont) 
    4. plt.axis('on') 
    5. plt.xticks([]) 
    6. plt.yticks([]) 
    7. plt.show() 
    8.  
    9. path1 = nx.single_source_shortest_path(G, 0) #计算当前源与所有可达节点的最短路径 
    10. length1 = nx.single_source_shortest_path_length(G, 0) #计算当前源与所有可达节点的最短路径的长度 
    11. path2 = dict(nx.all_pairs_shortest_path(G)) #计算graph两两节点之间的最短路径 
    12. length2 = dict(nx.all_pairs_shortest_path_length(G)) #计算graph两两节点之间的最短路径的长度 
    13. prede1=nx.predecessor(G, 0) #返回G中从源到所有节点最短路径的前驱 
    14.  
    15. print('当前源与所有可达节点的最短路径: ',path1,' 当前源与所有可达节点的最短路径的长度: ',length1) 
    16. print(' graph两两节点之间的最短路径: ',path2,' graph两两节点之间的最短路径的长度: ',length2) 
    17. print(' G中从源到所有节点最短路径的前驱: ',prede1) 

    无权图
    无权图

    输出:

    1. 当前源与所有可达节点的最短路径: {0: [0], 1: [0, 1], 2: [0, 1, 2]}  
    2. 当前源与所有可达节点的最短路径的长度: {0: 0, 1: 1, 2: 2} 
    3. 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]}}  
    4. graph两两节点之间的最短路径的长度: {0: {0: 0, 1: 1, 2: 2}, 1: {0: 1, 1: 0, 2: 1}, 2: {0: 2, 1: 1, 2: 0}} 
    5. G中从源到所有节点最短路径的前驱: {0: [], 1: [0], 2: [1]} 

    11.1.3有权图(迪杰斯特拉)

    1. G = nx.path_graph(5, create_using = nx.DiGraph())  
    2. nx.draw(G,with_labels=True) 
    3. plt.title('有向图',fontproperties=myfont) 
    4. plt.axis('on') 
    5. plt.xticks([]) 
    6. plt.yticks([]) 
    7. plt.show() 
    8.  
    9. #计算加权图最短路径长度和前驱 
    10. pred, dist = nx.dijkstra_predecessor_and_distance(G, 0) 
    11. print(' 加权图最短路径长度和前驱: ',pred, dist) 
    12.  
    13. #返回G中从源到目标的最短加权路径,要求边权重必须为数值 
    14. print(' G中从源0到目标4的最短加权路径: ',nx.dijkstra_path(G,0,4)) 
    15. print(' G中从源0到目标4的最短加权路径的长度: ',nx.dijkstra_path_length(G,0,4)) #最短路径长度 
    16.  
    17. #单源节点最短加权路径和长度。 
    18. length1, path1 = nx.single_source_dijkstra(G, 0) 
    19. print(' 单源节点最短加权路径和长度: ',length1, path1) 
    20. #下面两条和是前面的分解 
    21. # path2=nx.single_source_dijkstra_path(G,0) 
    22. # length2 = nx.single_source_dijkstra_path_length(G, 0) 
    23. #print(length1,'$', path1,'$',length2,'$',path2) 
    24.  
    25. #多源节点最短加权路径和长度。 
    26. path1 = nx.multi_source_dijkstra_path(G, {0, 4}) 
    27. length1 = nx.multi_source_dijkstra_path_length(G, {0, 4}) 
    28.  
    29. print(' 多源节点最短加权路径和长度:', path1,length1) 
    30.  
    31. #两两节点之间最短加权路径和长度。 
    32. path1 = dict(nx.all_pairs_dijkstra_path(G)) 
    33. length1 = dict(nx.all_pairs_dijkstra_path_length(G)) 
    34. print(' 两两节点之间最短加权路径和长度: ',path1,length1) 
    35.  
    36. #双向搜索的迪杰斯特拉 
    37. length, path = nx.bidirectional_dijkstra(G, 0, 4) 
    38. print(' 双向搜索的迪杰斯特拉:',length, path) 

    迪杰斯特拉算法使用
    迪杰斯特拉算法使用

    输出:

    1. 加权图最短路径长度和前驱: {0: [], 1: [0], 2: [1], 3: [2], 4: [3]} {0: 0, 1: 1, 2: 2, 3: 3, 4: 4} 
    2. G中从源0到目标4的最短加权路径: [0, 1, 2, 3, 4] 
    3. G中从源0到目标4的最短加权路径的长度: 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]} 
    5. 多源节点最短加权路径和长度: {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} 
    6. 两两节点之间最短加权路径和长度: {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}} 
    7. 双向搜索的迪杰斯特拉: 4 [0, 1, 2, 3, 4] 

    11.1.4贝尔曼-福特(Bellman-Ford)算法

    1. G = nx.path_graph(5, create_using = nx.DiGraph())  
    2. nx.draw(G,with_labels=True) 
    3. plt.title('有权图',fontproperties=myfont) 
    4. plt.axis('on') 
    5. plt.xticks([]) 
    6. plt.yticks([]) 
    7. plt.show() 
    8.  
    9. print('G中从源到目标的最短加权路径: ',nx.bellman_ford_path(G, 0, 4)) 
    10. print(' G中从源到目标的最短加权路径的长度:',nx.bellman_ford_path_length(G,0,4)) 
    11.  
    12. path1=nx.single_source_bellman_ford_path(G,0) 
    13. length1 = dict(nx.single_source_bellman_ford_path_length(G, 0)) 
    14. print(' 单源节点最短加权路径和长度: ',path1,' 单源节点最短加权路径和长度: ',length1) 
    15.  
    16. path2 = dict(nx.all_pairs_bellman_ford_path(G)) 
    17. length2 = dict(nx.all_pairs_bellman_ford_path_length(G)) 
    18. print(' 两两节点之间最短加权路径和长度: ',path2,length2) 
    19.  
    20. length, path = nx.single_source_bellman_ford(G, 0) 
    21. pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) 
    22. print(' 加权图最短路径长度和前驱: ',pred,dist) 

    贝尔曼-福特(Bellman-Ford)算法使用示例
    贝尔曼-福特(Bellman-Ford)算法使用示例

    输出:

    1. G中从源到目标的最短加权路径: [0, 1, 2, 3, 4] 
    2. G中从源到目标的最短加权路径的长度: 4 
    3. 单源节点最短加权路径和长度: {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}  
    4. 单源节点最短加权路径和长度: {0: 0, 1: 1, 2: 2, 3: 3, 4: 4} 
    5. 两两节点之间最短加权路径和长度: {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检测负权重边

    1. #定义并画出该图 
    2. G = nx.cycle_graph(5, create_using = nx.DiGraph()) 
    3.  
    4. #添加负权重边前后 
    5. print(nx.negative_edge_cycle(G)) 
    6. G[1][2]['weight'] = -7 
    7. print(nx.negative_edge_cycle(G)) 

    输出:

    1. False 
    2. True 

    11.1.6使用约翰逊(Johnson)的算法

    1. #生成graph 
    2. G = nx.DiGraph() 
    3. G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5),('0', '2', 2), ('1', '2', 4), ('2', '3', 1)]) 
    4.  
    5. #边和节点信息 
    6. edge_labels = nx.get_edge_attributes(G,'weight')  
    7. labels={'0':'0','1':'1','2':'2','3':'3'} 
    8.  
    9. #生成节点位置  
    10. pos=nx.spring_layout(G)  
    11.  
    12. #把节点画出来  
    13. nx.draw_networkx_nodes(G,pos,node_color='g',node_size=500,alpha=0.8)  
    14.  
    15. #把边画出来  
    16. nx.draw_networkx_edges(G,pos,width=1.0,alpha=0.5,edge_color='b')  
    17.  
    18. #把节点的标签画出来  
    19. nx.draw_networkx_labels(G,pos,labels,font_size=16)  
    20.  
    21. #把边权重画出来  
    22. nx.draw_networkx_edge_labels(G, pos, edge_labels)  
    23.  
    24. #显示graph 
    25. plt.title('有权图',fontproperties=myfont) 
    26. plt.axis('on') 
    27. plt.xticks([]) 
    28. plt.yticks([]) 
    29. plt.show() 
    30.  
    31. #使用johnson算法计算最短路径 
    32. paths = nx.johnson(G, weight='weight') 
    33.  
    34. print(paths) 

    约翰逊(Johnson)的算法使用示例
    约翰逊(Johnson)的算法使用示例

    输出:

    1. {'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)

    1. #使用Floyd算法找到所有对最短路径长度。 
    2. G = nx.DiGraph() 
    3. G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5),('0', '2', 2), ('1', '2', 4), ('2', '3', 1)]) 
    4.  
    5. #边和节点信息 
    6. edge_labels = nx.get_edge_attributes(G,'weight')  
    7. labels={'0':'0','1':'1','2':'2','3':'3'} 
    8.  
    9. #生成节点位置  
    10. pos=nx.spring_layout(G)  
    11.  
    12. #把节点画出来  
    13. nx.draw_networkx_nodes(G,pos,node_color='g',node_size=500,alpha=0.8)  
    14.  
    15. #把边画出来  
    16. nx.draw_networkx_edges(G,pos,width=1.0,alpha=0.5,edge_color='b')  
    17.  
    18. #把节点的标签画出来  
    19. nx.draw_networkx_labels(G,pos,labels,font_size=16)  
    20.  
    21. #把边权重画出来  
    22. nx.draw_networkx_edge_labels(G, pos, edge_labels)  
    23.  
    24. #显示graph 
    25. plt.title('有权图',fontproperties=myfont) 
    26. plt.axis('on') 
    27. plt.xticks([]) 
    28. plt.yticks([]) 
    29. plt.show() 
    30.  
    31. #计算最短路径长度 
    32. lenght=nx.floyd_warshall(G, weight='weight') 
    33.  
    34. #计算最短路径上的前驱与路径长度 
    35. predecessor,distance1=nx.floyd_warshall_predecessor_and_distance(G, weight='weight') 
    36.  
    37. #计算两两节点之间的最短距离,并以numpy矩阵形式返回 
    38. distance2=nx.floyd_warshall_numpy(G, weight='weight') 
    39.  
    40. print(list(lenght)) 
    41. print(predecessor) 
    42. print(list(distance1)) 
    43. print(distance2) 

    弗洛伊德算法(Floyd-Warshall)使用示例
    弗洛伊德算法(Floyd-Warshall)使用示例

    输出:

    1. ['2', '3', '0', '1'] 
    2. {'2': {'3': '2'}, '0': {'2': '1', '3': '2', '1': '0'}, '1': {'2': '1', '3': '2'}} 
    3. ['2', '3', '0', '1'] 
    4. [[ 0. 1. inf inf] 
    5. [inf 0. inf inf] 
    6. [-1. 0. 0. -5.] 
    7. [ 4. 5. inf 0.]] 

    注:输出中的矩阵不是按照节点0,1,2,3排序,而是2,1,3,0,即如图:


    两点之间的最短距离


    11.1.8A*算法

    1. G = nx.path_graph(5) 
    2.  
    3. #显示graph 
    4. nx.draw(G,with_labels=True) 
    5. plt.title('有x向图',fontproperties=myfont) 
    6. plt.axis('on') 
    7. plt.xticks([]) 
    8. plt.yticks([]) 
    9. plt.show() 
    10.  
    11. #直接输出路径和长度 
    12. print(nx.astar_path(G, 0, 4)) 
    13. print(nx.astar_path_length(G, 0, 4)) 

    A*算法
    A*算法

    输出:

    1. [0, 1, 2, 3, 4] 
    2. 4 
  • 相关阅读:
    Backbone.js 1.0.0源码架构分析(一)
    汤姆大叔的博客(深入理解JavaScript系列(2):揭秘命名函数表达式)
    求职之路(拿到百度、美团、趋势科技、华为offer)
    请大家注意这个网站www.haogongju.net
    后缀数组求最长重复子串
    2015阿里在线笔试题求两个字符串的最长子串
    剑指offer42:翻转单词顺序 VS 左旋转字符串(更高效、简便的解法)
    求和为s的连续正数序列
    数组中的逆序对
    求一串字符串的全排列和所有组合
  • 原文地址:https://www.cnblogs.com/wushaogui/p/9239735.html
Copyright © 2011-2022 走看看