图论Dijkstra Algorithm在2D空间平面网格节点图选择最短路径,networkx,Python

x33g5p2x  于2021-12-02 转载在 Go  
字(4.6k)|赞(0)|评价(0)|浏览(511)

图论Dijkstra Algorithm在2D空间平面网格节点图选择最短路径,networkx,Python

(1)Dijkstra Algorithm算法结束后,在代码生成的二维网格图中所有节点的权值即为出发点(源点)到当前节点的最短路径。本例中网格图中所有邻接边权值为1。

(2)通过每个节点中保存的parent指针一路逆行往上迭代查找,直到出发点(源点),即为出发点到当前节点的最短路径。parent指针指向了到当前节点的最短路径父节点。

(3)Dijkstra Algorithm寻路结束后,出发点(源点)到所有可达点的最短距离确定(weight值即为最短路径值)。从中可以得到启发,比如多人对战游戏,一张地图中同一时刻多人需要知道到达某汇聚点的路径,那么这种算法应用场景,Dijkstra Algorithm就很适合(反而A算法在这种应用场景不适合,因为A算法确定的是一个出发点到一个终点的路线。如果是N个人,就需要N次运行A*算法,才能为N个人完成选路),而Dijkstra Algorithm只需一次寻路,就完成所有地图中的点(某个点代表某个人的位置)到某个源点的最短距离。

(4)Dijkstra Algorithm在本例中作为一种广度优先搜索寻找最短路径,在每个节点中加入的parent指针,将其形成一定程度具有深度的寻路思想。这种思想在寻路算法中很普遍,在广度和深度的搜索过程中,通过埋入一个指针parent,可以快速找到出发点到源点的最短路径。

  1. import random
  2. import networkx as nx
  3. import matplotlib.pyplot as plt
  4. WALKABLE = 'walkable'
  5. PARENT = 'parent'
  6. WEIGHT = 'weight'
  7. def my_graph():
  8. M = 7
  9. N = 9
  10. G = nx.grid_2d_graph(m=M, n=N)
  11. pos = nx.spring_layout(G, iterations=100)
  12. nx.draw_networkx(G, pos=pos,
  13. # labels=labels, #labels = dict(((i, j), 'Phil') for i, j in G.nodes())
  14. font_size=8,
  15. font_color='white',
  16. node_color='green',
  17. node_size=500,
  18. width=1)
  19. START = (1, 1)
  20. GOAL = (M - 1 - 1, N - 1 - 1)
  21. # 0,随机生成障碍物点
  22. # 1,精心挑选的障碍物构成陷阱
  23. OBSTACLE_MODE = 0
  24. road_closed_nodes = []
  25. if OBSTACLE_MODE == 0:
  26. obstacle_number = 20 # 障碍物(断点、不可达点)数量
  27. road_closed_nodes = obstacle_nodes(G, START, GOAL, obstacle_number, M, N)
  28. elif OBSTACLE_MODE == 1:
  29. road_closed_nodes = dummy_nodes(G)
  30. nx.draw_networkx_nodes(
  31. G, pos,
  32. nodelist=road_closed_nodes,
  33. node_size=500,
  34. node_color="red",
  35. node_shape="x",
  36. # alpha=0.3,
  37. label='x'
  38. )
  39. dijkstra_find_path(G, START, G.number_of_nodes() - len(road_closed_nodes))
  40. print('G.nodes(data=True) 更新节点权值后', G.nodes(data=True))
  41. path = find_path_by_parent(G, START, GOAL)
  42. print('path', path)
  43. nx.draw_networkx_nodes(
  44. G, pos,
  45. nodelist=path,
  46. node_size=400,
  47. node_color="red",
  48. node_shape='o',
  49. # alpha=0.3,
  50. # label='NO'
  51. )
  52. path_edges = []
  53. for i in range(len(path)):
  54. if (i + 1) == len(path):
  55. break
  56. path_edges.append((path[i], path[i + 1]))
  57. print('path_edges', path_edges)
  58. # 把path着色加粗重新描边
  59. nx.draw_networkx_edges(G, pos,
  60. edgelist=path_edges,
  61. width=8,
  62. alpha=0.5,
  63. edge_color="r")
  64. plt.axis('off')
  65. plt.show()
  66. def dijkstra_find_path(G, START, valid_node_number):
  67. # 设置所有节点的权值为无穷大
  68. for n in G.nodes():
  69. G.nodes[n][WEIGHT] = float('inf')
  70. # 更新出发节点权重为0
  71. G.nodes[START][WEIGHT] = 0
  72. print('G.nodes(data=True)', G.nodes(data=True))
  73. print('起点', START)
  74. close_list = []
  75. vertex = START # 顶点
  76. while True:
  77. print('-----')
  78. if len(close_list) == valid_node_number:
  79. print('搜索完毕')
  80. break
  81. update_weight_from_node(G, vertex, close_list)
  82. min_node = find_min_nodes(G, vertex, close_list)
  83. vertex = min_node[0]
  84. close_list.append(vertex)
  85. def update_weight_from_node(G, cur_node, close_list):
  86. cur_node_weight = G.nodes[cur_node][WEIGHT]
  87. neighbors = nx.neighbors(G, cur_node)
  88. for child in neighbors:
  89. try:
  90. walkable = G.nodes[child][WALKABLE]
  91. except:
  92. walkable = True
  93. if (child in close_list) or (not walkable):
  94. continue
  95. edge_weight = 1 # 在本例的2D平面图中,邻接的边权都是1
  96. child_node_weight = G.nodes[child][WEIGHT]
  97. sum_weight = cur_node_weight + edge_weight
  98. if sum_weight < child_node_weight:
  99. G.nodes[child][WEIGHT] = sum_weight
  100. G.nodes[child][PARENT] = cur_node
  101. print('更新节点权值', cur_node, '->', child, '新权值为:', sum_weight)
  102. def find_min_nodes(G, vertex, close_list):
  103. node_list = []
  104. for node in G.nodes(data=True):
  105. try:
  106. walkable = node[1][WALKABLE]
  107. except:
  108. walkable = True
  109. if walkable and (node[0] not in close_list) and (node[0] != vertex):
  110. node_list.append(node)
  111. min_node = min(node_list, key=lambda x: x[1][WEIGHT])
  112. print(vertex, '最小节点', min_node)
  113. return min_node
  114. def find_path_by_parent(G, START, GOAL):
  115. t = GOAL
  116. path = [t]
  117. is_find = False
  118. while not is_find:
  119. for n in G.nodes(data=True):
  120. if n[0] == t:
  121. parent = n[1][PARENT]
  122. path.append(parent)
  123. if parent == START:
  124. is_find = True
  125. break
  126. t = parent
  127. list.reverse(path)
  128. return path
  129. # 障碍物点
  130. def obstacle_nodes(G, START, GOAL, obstacle, M, N):
  131. road_closed_nodes = []
  132. for i in range(obstacle):
  133. n = (random.randint(0, M - 1), random.randint(0, N - 1))
  134. if n == START or n == GOAL:
  135. continue
  136. if n in road_closed_nodes:
  137. continue
  138. G.nodes[n][WALKABLE] = False
  139. road_closed_nodes.append(n)
  140. return road_closed_nodes
  141. def dummy_nodes(G):
  142. fun_nodes = []
  143. n0 = (1, 2)
  144. G.nodes[n0][WALKABLE] = False
  145. fun_nodes.append(n0)
  146. n1 = (1, 3)
  147. G.nodes[n1][WALKABLE] = False
  148. fun_nodes.append(n1)
  149. n2 = (1, 4)
  150. G.nodes[n2][WALKABLE] = False
  151. fun_nodes.append(n2)
  152. n3 = (1, 5)
  153. G.nodes[n3][WALKABLE] = False
  154. fun_nodes.append(n3)
  155. n4 = (1, 6)
  156. G.nodes[n4][WALKABLE] = False
  157. fun_nodes.append(n4)
  158. n5 = (2, 6)
  159. G.nodes[n5][WALKABLE] = False
  160. fun_nodes.append(n5)
  161. n6 = (3, 6)
  162. G.nodes[n6][WALKABLE] = False
  163. fun_nodes.append(n6)
  164. n7 = (4, 6)
  165. G.nodes[n7][WALKABLE] = False
  166. fun_nodes.append(n7)
  167. n8 = (5, 6)
  168. G.nodes[n8][WALKABLE] = False
  169. fun_nodes.append(n8)
  170. n9 = (5, 5)
  171. G.nodes[n9][WALKABLE] = False
  172. fun_nodes.append(n9)
  173. n10 = (5, 4)
  174. G.nodes[n10][WALKABLE] = False
  175. fun_nodes.append(n10)
  176. n11 = (5, 3)
  177. G.nodes[n11][WALKABLE] = False
  178. fun_nodes.append(n11)
  179. n12 = (5, 2)
  180. G.nodes[n12][WALKABLE] = False
  181. fun_nodes.append(n12)
  182. return fun_nodes
  183. if __name__ == '__main__':
  184. my_graph()

运行几轮后的选路截图:

当把障碍物模式切换为1,即特意挑选一批点围成一个围墙,同时把出发点改为(2,2),看看算法的表现:

算法聪明的规避了围墙,没有跳进凹形陷阱。 

相关文章

最新文章

更多