路徑規划問題:DIJKSTRA算法 以及Python實現


參考: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分成兩組:  [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] 
若存在<V0,Vi>,d(V0,Vi)為<V0,Vi>弧上的權值  [1] 
若不存在<V0,Vi>,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 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']

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM