long long ago就已經知道了floyd演算法,關鍵**就4行,也容易記住,上上週又看到了floyd,都說是動態規劃,所以特意去學了一圈動態規劃,今天終於又回到了它
d[k][i][j]定義:「只能使用第1號到第k號點作為中間媒介時,點i到點j之間的最短路徑長度。」
在動態規劃演算法中,處於首要位置、且也是核心理念之一的就是狀態的定義
這個大家喜歡把它叫做「鬆弛操作」,也就是relax
對於d[k][i][j](即使用1號到k號點中的所有點作為中間媒介時,i和j之間的最短路徑),可以分為兩種情況:
1)i到j的最短路不經過k;(
2)i到j的最短路經過了k。不經過點k的最短路情況下,d[k][i][j]=d[k-1][i][j]。經過點k的最短路情況下,d[k][i][j]=d[k-1][i][k]+d[k-1][k][j]。
因此,綜合上述兩種情況,便可以得到floyd演算法的動態轉移方程:
d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j])(k,i,j∈[1,n])
初始條件:d[0][i][j]=w(i, j),d[k][0][j]=0,d[k][i][0]=0
# d[k][i][j] = min(d[k-1][i][j], d[k-1][i][k]+d[k-1][k][j])(k,i,j∈[1,n])
import numpy as np
deffloyd_original
(graph)
: vertex_num =
len(graph)
list
= np.full(
(vertex_num+
1,vertex_num+
1,vertex_num+1)
,np.inf)
list[:
,0,:
]=0list[:
,:,0
]=0for i in
range(1
,vertex_num+1)
:for j in
range(1
,vertex_num+1)
:list[0
,i,j]
= graph[i-
1,j-1]
for k in
range(1
,vertex_num+1)
:for i in
range(1
,vertex_num+1)
:for j in
range(1
,vertex_num+1)
:list
[k,i,j]
=min
(list
[k-1
,i,j]
,list
[k-1
,i,k]
+list
[k-1
,k,j]
)return
list
[vertex_num,1:
,1:]
d[k][i][k]
= min(d[k-1][i][k], d[k-1][i][k]+d[k-1][k][k])
= min(d[k-1][i][k], d[k-1][i][k]+0)
= d[k-1][i][k]
也就是說在第k-1階段和第k階段,點i和點k之間的最短路徑長度是不變的。相同可以證明,在這兩個階段中,點k和點j之間的的最短路徑長度也是不變的。因此,對於使用滾動陣列的轉移方程d[i][j] = min(d[i][j], d[i][k]+d[k][j])來說,賦值號右側的d[i][j], d[i][k]和d[k][j]的值都是上一階段(k-1階段)的值,可以放心地被用來計算第k階段時d[i][j]的值。
有沒有很坑? 繞了一圈又回到不熟悉的東西上去了
仔細看一遍上述的公式就懂了。
所以我們可以使用滾動陣列來優化空間。
import numpy as np
deffloyd
(graph)
: vertex_num =
len(graph)
list
= np.zeros(
(vertex_num+
1,vertex_num+1)
)for i in
range(1
,vertex_num+1)
:for j in
range(1
,vertex_num+1)
:list
[i,j]
= graph[i-
1,j-1]
for k in
range(1
,vertex_num+1)
:for i in
range(1
,vertex_num+1)
:for j in
range(1
,vertex_num+1)
:list
[i,j]
=min
(list
[i,j]
,list
[i,k]
+list
[k,j]
)return
list[1
:,1:
]
#%%
graph = np.full((7
,7),np.inf)
graph[0,
:3]=
[0,1
,2]graph[1,
:4]=
[1,0
,3,4
]graph[2,
:4]=
[2,3
,0,6
]graph[3,
1:5]
=[4,
6,0,
7]graph[4,
3:6]
=[7,
0,9]
graph[5,
4:7]
=[9,
0,10]
graph[6,
5:7]
=[10,
0]print floyd_original(graph)
print floyd(graph)[[
0.1.
2.5.
12.21.
31.][
1.0.
3.4.
11.20.
30.][
2.3.
0.6.
13.22.
32.][
5.4.
6.0.
7.16.
26.][
12.11.
13.7.
0.9.
19.][
21.20.
22.16.
9.0.
10.][
31.30.
32.26.
19.10.
0.]]
[[0.
1.2.
5.12.
21.31.
][1.
0.3.
4.11.
20.30.
][2.
3.0.
6.13.
22.32.
][5.
4.6.
0.7.
16.26.
][12.
11.13.
7.0.
9.19.
][21.
20.22.
16.9.
0.10.
][31.
30.32.
26.19.
10.0.
]]
動態規劃 最短路徑 Floyd演算法
正如我們所知道的,floyd演算法用於求最短路徑。floyd演算法可以說是warshall演算法的擴充套件,三個for迴圈就可以解決問題,所以它的時間複雜度為o n 3 floyd演算法的基本思想如下 從任意節點a到任意節點b的最短路徑不外乎2種可能 1是直接從a到b 2是從a經過若干個節點x到b。...
探求Floyd演算法的動態規劃本質
floyd warshall 簡稱floyd演算法 是一種著名的解決任意兩點間的最短路徑 all paris shortest paths,apsp 的演算法。從表面上粗看,floyd演算法是乙個非常簡單的三重迴圈,而且純粹的floyd演算法的迴圈體內的語句也十分簡潔。我認為,正是由於 floyd演...
Floyd 動態規劃的理解
這裡我一直好奇的是這三個漂亮的迴圈是怎麼完成最終正確的結果的,如何證明它們是正確的。直到看了這裡的解析,才算弄懂了。floyd演算法是乙個經典的動態規劃演算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。從動態規劃的角度看問題,我們需要為這個目標重新做乙個詮釋 這個詮釋正是動...