一. DJKSTRA算法概述

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

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

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

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

把顶点集合V分成两组:[3]

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

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

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

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

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

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

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

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

(反证法可证)

求最短路径步骤[1]

算法步骤如下:[1]

G={V,E}

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

若存在,d(V0,Vi)为弧上的权值[1]

若不存在,d(V0,Vi)为∞[2]

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

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

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

二. 示例问题

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


第一步:

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

A

B

C

D

E

F

G

0

第二步:

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

找到:

A - B;  权重8

A - D;  权重10

A - E;  权重12


第三步:

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

找到:

A - B - C  14

A - B - F   20


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


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

三. Python代码实现

1 #!/usr/bin/python3
2 #-*- coding: utf-8 -*-
3 #@author: Asp1rant
4
5
6 defdjkstra(graph, start, end):7 path_set = set() #已求的路径集合
8 priority_dic ={}9 for k ingraph.keys():10 priority_dic[k] = [9999, False, ""] #权重表构建为一个3维数组,分别是:最小路径代价,是否计算过最小边,最小路径
11 priority_dic[start][0] =012
13 #判断权重表中所有路点是否添加完毕
14 defisSelectAll():15 ret =True16 for val inpriority_dic.values():17 if not val[1]:18 ret =False19 break
20 returnret21
22 while notisSelectAll():23 find_point =start24 find_path =start25 min_distance = 9999
26 for path inpath_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_point31 find_path =path32 min_distance =path_distance33 find_distance =priority_dic[find_point][0]34 neighbors =graph[find_point]35 for k inneighbors.keys():36 p = find_path + "-" +k37 weight = find_distance +neighbors[k]38 path_set.add(p)39 if weight 
44 returnpriority_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']