floyd演算法 多源最短路徑 python實現

2021-09-24 18:42:38 字數 4278 閱讀 5762

floyd(弗洛伊德)演算法用來找每個點兩兩之間的最短距離(多源最短路徑),是典型的動態規劃

原理很簡單:

乙個點 i 到另乙個點 j 的最短路徑無非有兩種:

直接到達( i --> j )

通過走其他點(k1, k2 … kn),乙個或多個點到達( i --> k1–>k2–> … --> j )

所以找最短路就直接 比較 1 和 2 哪條路徑更短

資料結構:鄰接矩陣(n*n) graph, graph[ i ][ j ]表示 i --> j 的最短路徑。

初始化:一開始全設為無窮大,如果 i == j , graph[ i ][ j ] == 0,然後遍歷所有圖中的所有邊 i --> j ,令 graph[ i ][ j ] = 邊權

要找到 i 到 j 的最短路徑,我們需要 i 去經過另外的結點再走回 j(i --> k --> j),看和原路徑(i --> j)誰更短,然後更新graph[ i ][ j ]。要得出這個結果就得每個結點都走一遍。

這裡作個演示。比如我們可以先只經過編號為 1 的結點,比較 i --> j 和 i --> 1–> j,哪條路小,然後更新 i --> j的最短路徑

graph[ i ][ j ] = min ( graph[ i ][ j ], graph[ i ][ 1 ] + graph[ 1 ][ j ] )

for i in

range

(n):

for j in

range

(n):

graph[i]

[j]=

min(graph[i]

[j], graph[i][1

]+ graph[1]

[j])

同理經過其他點,比如編號為2的點

for i in

range

(n):

for j in

range

(n):

graph[i]

[j]=

min(graph[i]

[j], graph[i][2

]+ graph[2]

[j])

最後我們每個點都要經過:

for k in

range

(n):

for i in

range

(n):

for j in

range

(n):

graph[i]

[j]=

min(graph[i]

[j], graph[i]

[k]+ graph[k]

[j])

是不是很簡單。。。核心**就只有4行**。。。

因為每次 i --> j 的路徑都更新為最優的而且都被儲存下來,所以後面的結點要通過這個結點去往別的結點,就能保證是最優的。

例子:來自:

這篇部落格裡面講的更詳細

如果要列印路徑,我們就需要用乙個二維陣列parents記錄每個結點的父結點。在找最短路的時候,更新父結點。最後遞迴尋找父結點,回溯列印。

import sys

sys.setrecursionlimit(

100000000

)# 弗洛伊德演算法

deffloyd()

: n =

len(graph)

for k in

range

(n):

for i in

range

(n):

for j in

range

(n):

if graph[i]

[k]+ graph[k]

[j]< graph[i]

[j]:

graph[i]

[j]= graph[i]

[k]+ graph[k]

[j] parents[i]

[j]= parents[k]

[j]# 更新父結點

# 列印路徑

defprint_path

(i, j)

:if i != j:

print_path(i, parents[i]

[j])

print

(j, end=

'-->'

)# data [u, v, cost]

datas =[[

0,1,

2],[

0,2,

6],[

0,3,

4],[

1,2,

3],[

2,0,

7],[

2,3,

1],[

3,0,

5],[

3,2,

12],]

n =4

# 無窮大

inf =

9999999999

# 構圖

graph =[[

(lambda x:

0if x[0]

== x[1]

else inf)

([i, j]

)for j in

range

(n)]

for i in

range

(n)]

parents =

[[i]

* n for i in

range(4

)]# 關鍵地方,i-->j 的父結點初始化都為i

for u, v, c in datas:

graph[u]

[v]= c # 因為是有向圖,邊權只賦給graph[u][v]

#graph[v][u] = c # 如果是無向圖,要加上這條。

floyd(

)print

('costs:'

)for row in graph:

for e in row:

print

('∞'

if e == inf else e, end=

'\t'

)print()

print

('\npath:'

)for i in

range

(n):

for j in

range

(n):

print

('path({}-->{}): '

.format

(i, j)

, end='')

print_path(i, j)

print

(' cost:'

, graph[i]

[j])

# 最終的graph

# graph[i][j]表示i-->j的最短路徑

# 0 2 5 4

# 9 0 3 4

# 6 8 0 1

# 5 7 10 0

## path:

# path(0-->0): 0--> cost: 0

# path(0-->1): 0-->1--> cost: 2

# path(0-->2): 0-->1-->2--> cost: 5

# path(0-->3): 0-->3--> cost: 4

# path(1-->0): 1-->2-->3-->0--> cost: 9

# path(1-->1): 1--> cost: 0

# path(1-->2): 1-->2--> cost: 3

# path(1-->3): 1-->2-->3--> cost: 4

# path(2-->0): 2-->3-->0--> cost: 6

# path(2-->1): 2-->3-->0-->1--> cost: 8

# path(2-->2): 2--> cost: 0

# path(2-->3): 2-->3--> cost: 1

# path(3-->0): 3-->0--> cost: 5

# path(3-->1): 3-->0-->1--> cost: 7

# path(3-->2): 3-->0-->1-->2--> cost: 10

# path(3-->3): 3--> cost: 0

Floyd演算法 多源最短路徑

解決稠密圖較好 準備工作 include floyd演算法解決稠密圖時更好 include include include using namespace std const int maxv 100 定義邊 typedef struct enode edge 定義鄰接矩陣儲存的圖 typedef ...

Floyd 演算法求多源最短路徑

floyd演算法 floyd演算法用來找出每對頂點之間的最短距離,它對圖的要求是,既可以是無向圖也可以是有向圖,邊權可以為負,但是不能存在負環 可根據最小環的正負來判定 基本演算法 floyd演算法基於動態規劃的思想,以 u 到 v 的最短路徑至少經過前 k 個點為轉移狀態進行計算,通過 k 的增加...

Floyd 演算法求多源最短路徑

floyd演算法 floyd演算法用來找出每對頂點之間的最短距離,它對圖的要求是,既可以是無向圖也可以是有向圖,邊權可以為負,但是不能存在負環 可根據最小環的正負來判定 基本演算法 floyd演算法基於動態規劃的思想,以 u 到 v 的最短路徑至少經過前 k 個點為轉移狀態進行計算,通過 k 的增加...