最短路算法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()
运行结果: