JavaScript與Floyd最短路演算法
背景
NBA超級後場組合燈泡組合(Harden和CP3)休賽期來到中國玩耍,他們兩人打算在四個城市進行玩耍,最後他們選擇了北京、上海、西安和長沙。假設這四個城市之間有些城市之前有航線,而有些城市之間沒有航線。為了方便行程,出發前,他們想要知道任意兩個城市之間的最短路程。如果下圖就是航線圖:
資料結構
我們使用一個二維陣列Path來儲存上述圖的資訊。比如說0號城市到1號城市之間的距離可以儲存為Path[0][1] = 2,而1號城市無法直接到達0號城市我們記Path[1][0] = Infinity。另外我們約定一個城市到達本身的距離為0,即Path[0][0] = 0。
思路
想要使兩個城市(x
過程
我們依照最上面的航線圖,解釋如何得到最短路徑。
當任意兩個城市之間不允許經過第三個城市的時候,得到的矩陣如下:
第一步:
現在我們只允許經過0號城市這個中轉點,這個時候如何求解任意兩點之間的最短距離。我們只需進行如下比較:
Path[i ][0] + Path[0][j] < Path[i][j]
其中Path[i][j]表示的是城市i和j之間的距離。而Path[i][0] + Path[0][j] 表示的是先從i到0號城市,再從0到j的距離之和。
這個時候把i從0~n-1迴圈,把j從0~n-1迴圈,既可以得到當經過中轉點0號城市的時候,任意兩點之間的最短距離。
程式碼實現:
for(var i = 0; i < n; i++ ){
for(var j = 0; j < n; j++){
if(Path[i][0] + Path[0][j] < Path[i][j]){
Path[i][j] = Path[i][0 ] + Path[0][j];
}
}
}
這個時候我們可以把最短距離矩陣更新為:
從上圖可以看出,在經過中轉點:0號城市的時候,有幾個城市之間的最短距離減少了。
接下來,我們要做的就是增加中轉點:1號城市。要執行的程式碼如下:
for(var i = 0; i < n; i++ ){
for(var j = 0; j < n; j++){
if(Path[i][0] + Path[0][j] < Path[i][j]){
Path[i][j] = Path[i][0] + Path[0][j];
}
}
}
for(var i = 0; i < n; i++ ){
for(var j = 0; j < n; j++){
if(Path[i][1] + Path[1][j] < Path[i][j]){
Path[i][j] = Path[i][1] + Path[1][j];
}
}
}
我們可以繼續更新距離矩陣為:
從上圖可以看出,增加中轉點後,有些城市之間的最短距離進一步減小。
同理,我們進一步增加中轉點城市2和城市3,就可以得到最終的距離矩陣為:
下面給出一個完整函式:
//接收一個引數,引數即用二維陣列儲存的距離矩陣
function floyd(Path){
var n = Path && Path.length;
var m = n && Path[0].length;
if(m && n && m===n){
for(var k = 0; k < n; k++){
for(var i = 0; i < n; i++ ){
for(var j = 0; j < n; j++){
if(Path[i][k] + Path[k][j] < Path[i][j]){
Path[i][j] = Path[i][k] + Path[k][j];
}
}
}
}
}
}
注意:Floyd演算法不能解決帶有“負權迴路”(或者叫“負權環”)的圖。因為帶有“負權迴路”的圖沒有最短路。