最短路算法dijkstra的運用
尋找到達城市的最短路徑
如圖
1、一般用鄰接矩陣表示一個圖
鄰接矩陣:
A = [
if exist(A(i,j)):
return 1
else:
return 0
]
則一個圖的表示方法:
INF = 999
graph = [
[0, INF, INF, INF, INF, INF, INF, INF, INF, INF],
[4, 0, INF, INF, INF, INF, INF, INF, INF, INF],
[6, INF, 0, INF, INF, INF, INF, INF, INF],
[INF, 5, INF, 0, INF, INF, INF, INF, INF],
[INF, 7, 3, 3, 0, INF, INF, INF, INF, INF, INF],
[INF, INF, 13, INF, INF, 0, INF, INF, INF, INF],
[INF, INF, INF, 3, 2, INF, 0, INF, INF, INF],
[INF, INF, INF, INF, 9, 1, INF, 0, INF, INF],
[INF, INF, INF, INF, INF, 5, 3, 4, 0, INF]
]
2、爲了好看我們用地圖字典表示圖
graph = {
"北京": {"天津": 4, "蘇州": 6, "北京": 0},
"天津": {"上海": 5, "杭州": 7, "天津": 0},
"蘇州": {"杭州": 3, "鄭州": 13, "蘇州": 0},
"上海": {"杭州": 3, "福州": 3, "上海": 0},
"杭州": {"福州": 2, "合肥": 9, "杭州": 0},
"鄭州": {"合肥": 1, "廣州": 5, "鄭州": 0},
"福州": {"廣州": 3, "福州": 0},
"合肥": {"廣州": 4, "合肥": 0},
"廣州": {"廣州": 0}
}
3、dijkstra算法以及實現
(1)輸入:
- 1)圖graph
- 2)源點v0
(2)算法原理
1)一開始 S裏面只有源點 v0
2)離 v0最近的那個點爲 u,把 u放進 S,並且記錄這一次,到達 u的點和最短路
3)查看當前能夠到達的點,列出所有能夠到達的點它到源點的距離,排序後,最短的那個是新的 u
4)重複1-3,直到 S包含所有 graph的點
(3)定義變量:
1)有一個集合S,存放已經走過的點
2)有一個節點u,代表下一個要放進S的點
3)有一個數據結構dist{[shortest_path],<shortest_path_value>},用來存放最短路徑和最短路的值
4)有一個shortest_path{},以 <key,value> 的形式存放,最短路徑中,到達節點 key的上一個節點作爲 value 的值。
(4)代碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
INF = 999
class Dijkstra(object):
"""
用dijkstra求最短路,輸入參數爲一個圖和源點,graph實際是上一個二維數組,source表示的是二維數組中的第行個元素是源
時間複雜度O(n^2)
"""
def __init__(self, graph, source):
self.graph = graph
self.dist = {}
self.short_path = {}
self.s_collect = set()
self.source = source
def get_shortest_path_src_to_dest(self, des):
"""
獲取到達某目的地點的最短路信息
:param dis: 目的地點
:return:
"""
distance = self.get_shortest_path()
return distance[des]
def get_shortest_path(self):
"""
獲取全圖的所有最短路徑信息
:return:
"""
self._exec_shortest_path_calculation()
for key in self.dist.keys():
k = key
while k != self.source: # 獲取路徑
self.dist[key][0].insert(0, self.short_path[k])
k = self.short_path[k]
return self.dist
def _exec_shortest_path_calculation(self):
"""
計算最短路,得到圖中最短路的信息
:return:
"""
now_node = self.source
self.dist = dict((k, [[], INF]) for k in self.graph.keys()) # 假設初始化點到原點都是無限大
self.dist[now_node][1] = 0 # 源點到源點的距離爲0
while len(self.s_collect) < len(self.graph):
self.s_collect.add(now_node)
for next in self.graph[now_node]:
if self.dist[now_node][1] + self.graph[now_node][next] < self.dist[next][1]:
self.short_path[next] = now_node # next的點來自哪個節點
self.dist[next][1] = self.dist[now_node][1] + self.graph[now_node][next]
new_short = INF # 從剩下的未確定點中選擇最小距離點作爲新的擴散點
for now in self.dist.keys():
if now in self.s_collect:
continue
if self.dist[now][1] < new_short:
new_short = self.dist[now][1]
now_node = now
def print_path(source, short_path):
for key, path in short_path.items():
if key == source:
continue
path[0].append(key)
print("%s 到 %s 最短路徑爲:%s, 路徑: %s"
% (source, key, path[1], "->".join(path[0])))
def main():
source = "北京"
graph = {
"北京": {"天津": 4, "蘇州": 6, "北京": 0},
"天津": {"上海": 5, "杭州": 7, "天津": 0},
"蘇州": {"杭州": 3, "鄭州": 13, "蘇州": 0},
"上海": {"杭州": 3, "福州": 3, "上海": 0},
"杭州": {"福州": 2, "合肥": 9, "杭州": 0},
"鄭州": {"合肥": 1, "廣州": 5, "鄭州": 0},
"福州": {"廣州": 3, "福州": 0},
"合肥": {"廣州": 4, "合肥": 0},
"廣州": {"廣州": 0}
}
dj = Dijkstra(graph, source)
print_path(source, dj.get_shortest_path())
if __name__ == '__main__':
main()
運行結果:
4、鄰接矩陣和圖的字典表示法互換方法:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# adjacency martix
INF = 999
graph_mapper = {
0: "北京",
1: "天津",
2: "蘇州",
3: "上海",
4: "杭州",
5: "鄭州",
6: "福州",
7: "合肥",
8: "廣州"
}
graph = [
[0, 4, 6, INF, INF, INF, INF, INF, INF, ],
[INF, 0, INF, 5, 7, INF, INF, INF, INF, ],
[INF, INF, 0, INF, 3, 13, INF, INF, INF, ],
[INF, INF, INF, 0, 3, INF, 3, INF, INF, ],
[INF, INF, INF, INF, 0, INF, 2, 9, INF, ],
[INF, INF, INF, INF, INF, 0, INF, 1, 5, ],
[INF, INF, INF, INF, INF, INF, 0, INF, 3, ],
[INF, INF, INF, INF, INF, INF, INF, 0, 4, ],
[INF, INF, INF, INF, INF, INF, INF, INF, 0, ]
]
def adjacency_to_dictmap(graph_adjacency, graph_mapper):
"""
鄰接矩陣轉字典圖
:param graph_adjacency:
:return:
"""
graph_dict = {}
for i in range(len(graph_adjacency)):
graph_dict[graph_mapper[i]] = {}
for j in range(len(graph_adjacency[i])):
if graph_adjacency[i][j] != INF:
graph_dict[graph_mapper[i]][graph_mapper[j]] = graph_adjacency[i][j]
return graph_dict
def dictmap_to_adjacency(graph_dictmap, graph_mapper):
graph_mapper_re = dict(zip(graph_mapper.values(), graph_mapper.keys()))
print(graph_mapper_re)
def main():
graph_dict = adjacency_to_dictmap(graph, graph_mapper)
import pprint
pprint.pprint(graph_dict)
if __name__ == '__main__':
main()
運行結果: