要跑最短路,首先要有圖 ——
魯迅html
經常使用的存儲方法有兩種,分別是鄰接矩陣(用二維數組表示邊)和鄰接表(模擬鏈表表示邊)兩種,他們各有不一樣的優點和不足:python
鄰接矩陣 | 鄰接表 | |
---|---|---|
使用範圍 | 稠密圖 | 主要是稀疏圖 |
空間耗費 | n^2(n節點數) | 理論上是 e( e爲邊條數) |
實現方式 | 二維數組 | 存儲每一個節點相連的節點和邊權值 |
一般來說,在數據範圍足夠小時,咱們採用鄰接矩陣,而數據範圍大時採用鄰接表算法
鄰接矩陣實現:數組
無權圖:ide
g[x][y]=1 #g[x][y]=1表示x到y有一條邊鏈接 #g[y][x]=1 #去掉註釋後是無向圖
帶權圖:post
g[x][y]=w #g[x][y]=w表示x到y有一條權值爲w的邊 #g[y][x]=w #去掉註釋後是無向圖
多源最短路算法,用鄰接矩陣存儲,能夠處理負邊權,但不能處理負環測試
多源最短路就是說只要跑一次,任意兩點的最短路都能求啦( ̄︶ ̄),而其餘單源最短路跑一次只能得出一個點到其餘點的最短路ui
用鄰接矩陣存最短路( dis[i][j]
表示 i
到j
的最短距離)開一個三重循環(!)code
外層枚舉中間點,中間枚舉起點,內層枚舉終點,當三個點互不相同時進行鬆弛操做,若是通過中間點以後的路程和比原路程短,就更新距離,一輪事後,咱們獲得了一個新的矩陣,而後咱們把中間點換成下一個點,再次鬆弛,的到一個新的矩陣,執行 n
次以後,第 n
個矩陣就是咱們的答案啦orm
#提早將鄰接矩陣存在dis數組裏,其餘不連通的地方初始化成無窮大 for k in range(n): #枚舉中間點 for i in range(n): #枚舉起點 if(i!=k): #節省時間,若是同樣就不往下走 for j in range(n): #枚舉終點 if(i!=j and j!=k): #繼續判斷,若是有同樣的就不往下走 dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j])
單源最短路徑
將全部節點分紅兩類:已肯定從起點到當前點的最短路長度的節點,以及未肯定從起點到當前點的最短路長度的節點(下面簡稱「未肯定節點」和「已肯定節點」)。
每次從「未肯定節點」中取一個與起點距離最短的點,將它歸類爲「已肯定節點」,並用它「更新」從起點到其餘全部「未肯定節點」的距離。直到全部點都被歸類爲「已肯定節點」。
用節點 A「更新」節點 B 的意思是,用起點到節點 A 的最短路長度加上從節點 A 到節點 B 的邊的長度,去比較起點到節點 B 的最短路長度,若是前者小於後者,就用前者更新後者。這種操做也被叫作「鬆弛」。
這裏暗含的信息是:每次選擇「未肯定節點」時,起點到它的最短路徑的長度能夠被肯定。
——力扣(LeetCode)
def dijkstra(u): #初始化起點 u 到每個點的距離 for k in range(n): dis[k] = g[u][k] print("起點到其餘節點的初始距離:",dis) used[u] = 1 for k in range(n): minv = float('inf') #在未肯定節點中找與起點距離最短的 for i in range(n): if not used[i] and dis[i] < minv: minv = dis[i] temp = i #中轉位置, 變爲已肯定節點,更新距離 used[temp] = 1 for i in range(n): if g[temp][i]+dis[temp] < dis[i]: dis[i] = g[temp][i]+dis[temp] print("第 {} 次迭代,起點到其餘節點的距離:{}".format(k,dis))
測試下
with open("path.txt",'r') as f: n = int(f.readline()) weights = f.readlines() print("頂點數:",n) dis = [0]*n used = [0]*n # 定義鄰接矩陣存儲圖 g = [[0]*n for _ in range(n)] for u in range(n): for v in range(n): g[u][v] = int(weights[u].strip().split()[v]) print("鄰接矩陣:",g) # g[u][v] = g[v][u] = w # 建立圖,節點間沒有鏈接賦值爲 無窮大 dijkstra(0)
執行結果:
起點到其餘節點的初始距離: [65535, 33, 21, 26, 65535, 65535, 65535, 65535] 第 0 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 65535, 42, 65535, 65535] 第 1 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 96, 117] 第 2 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 96, 117] 第 3 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 71, 117] 第 4 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 71, 117] 第 5 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 71, 117] 第 6 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 71, 117] 第 7 次迭代,起點到其餘節點的距離:[42, 33, 21, 26, 62, 42, 71, 117]
附上數據
8 65535 33 21 26 65535 65535 65535 65535 65535 33 0 65535 27 30 65535 65535 65535 65535 21 65535 0 22 65535 21 65535 65535 65535 26 27 22 019 36 33 70 91 65535 30 65535 190 65535 41 64 80 65535 65535 21 36 65535 0 29 65535 65535 65535 65535 65535 33 41 290 22 65535 65535 65535 65535 70 64 65535 22 0 42
references:
http://www.javashuo.com/article/p-zcecsmme-no.html
https://www.luogu.com.cn/blog/FrozaFerrari/xue-tu-lun-ni-zhen-di-liao-xie-zui-duan-lu-ma-post
https://www.bilibili.com/video/BV1q4411M7r9/?spm_id_from=333.788.videocard.1