参考:http://www.banbeichadexiaojiubei.com/index.php/2020/02/26/%e8%87%aa%e5%8a%a8%e9%a9%be%e9%a9%b6%e8%b7%af%e5%be%84%e8%a7%84%e5%88%92-dijkstra%e7%ae%97%e6%b3%95/

 

一. DJKSTRA算法概述

我们可以将地图抽象为Graph的数据结构,然后利用Graph的广度优先遍历算法(Breadth-First Search, BFS)解决无权重的High-Level的地图级别的规划。但是实际应用场景中,地图中各个路径所代表的Graph的边的权重都是不同的,比如距离长的Edge权重就应该比较低;交通拥堵的Edge权重就应该低等等。对于有权重的Graph如何进行最短路径规划呢,Dijkstra算法可以解决这个问题。

Dijkstra算法是一种有权图(Graph)的单源最短路径求解算法,给定一个起点,使用Dijkstra算法可以得到起点到其它所有节点的最短路径。Dijkstra算法要求图(Graph)中所有边的权重都为非负值,只有保证了这个条件才能该算法的适用性和正确性。

 

算法思想:偷个懒,摘自百度百科

 

 

按路径长度递增次序产生算法:

把顶点集合V分成两组:

(1)S:已求出的顶点的集合(初始时只含有源点V0)

(2)V-S=T:尚未确定的顶点集合

将T中顶点按递增的次序加入到S中,保证:

(1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度

(2)每个顶点对应一个距离值

S中顶点:从V0到此顶点的长度

T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度

依据:可以证明V0到T中顶点Vk的,或是从V0到Vk的直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和

反证法可证)

求最短路径步骤

算法步骤如下:

G={V,E}

1. 初始时令 S={V0},T=V-S={其余顶点},T中顶点对应的距离值

若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值

若不存在<V0,Vi>,d(V0,Vi)为∞

2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中

3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值

重复上述步骤2、3,直到S  中包含所有顶点,即W=Vi为止

 

二. 示例问题

给出如下带权重的图,求从A到G的最短路径

python路径规划程序 python路径规划导航_权重

 

 

第一步:

构建一个记录最短路径和距离并用来计算权重的表格。初始化这个表格,除了起点A,已知距离为0,其它距离初始化为无穷大。

A

B

C

D

E

F

G

0







 

 

 

第二步:

以A为起点,可以得到从A出发的几条边,更新最短距离,并标记A为已计算过最小路径

找到:

A - B;  权重8

A - D;  权重10

A - E;  权重12

python路径规划程序 python路径规划导航_python路径规划程序_02

 

 

第三步:

遍历上一步找出的几条路径,选择最短路径,并计算其临边的所有路径,更新表格,并标记B为已找过的顶点

找到:

A - B - C  14

A - B - F   20

python路径规划程序 python路径规划导航_权重_03

 

 

第四步:不断重复第三步,直到所有顶点都找完为止

python路径规划程序 python路径规划导航_python路径规划程序_04

 

第五步:得到结果 A - B - F  - G

 

 

 

三. Python代码实现

 

1 #!/usr/bin/python3
 2 # -*- coding: utf-8 -*-
 3 # @author: Asp1rant
 4 
 5 
 6 def djkstra(graph, start, end):
 7     path_set = set()    # 已求的路径集合
 8     priority_dic = {}
 9     for k in graph.keys():
10         priority_dic[k] = [9999, False, ""] # 权重表构建为一个3维数组,分别是:最小路径代价,是否计算过最小边,最小路径
11     priority_dic[start][0] = 0
12 
13     # 判断权重表中所有路点是否添加完毕
14     def isSelectAll():
15         ret = True
16         for val in priority_dic.values():
17             if not val[1]:
18                 ret = False
19                 break
20         return ret
21 
22     while not isSelectAll():
23         find_point = start
24         find_path = start
25         min_distance = 9999
26         for path in path_set:
27             end_point = path[-1]
28             path_distance = priority_dic[end_point][0]
29             if path_distance < min_distance and not priority_dic[end_point][1]:
30                 find_point = end_point
31                 find_path = path
32                 min_distance = path_distance
33         find_distance = priority_dic[find_point][0]
34         neighbors = graph[find_point]
35         for k in neighbors.keys():
36             p = find_path + "-" + k
37             weight = find_distance + neighbors[k]
38             path_set.add(p)
39             if weight < priority_dic[k][0]:
40                 priority_dic[k][0] = weight
41                 priority_dic[k][2] = p
42         priority_dic[find_point][1] = True
43 
44     return priority_dic[end]
45 
46 
47 if __name__ == '__main__':
48     # 用于测试的图
49     graph = {
50                 "A": {"B": 8, "D": 10, "E": 12},
51                 "B": {"C": 6, "F": 12},
52                 "C": {"F": 8},
53                 "D": {"E": 10, "G": 30},
54                 "E": {"F": 10},
55                 "F": {"G": 12},
56                 "G": {}
57             }
58     result = djkstra(graph, "A", "G")
59     print(result)

 

 

 

输出结果:

[32, True, 'A-B-F-G']