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 的增加...