一、引言
哈嘍大家好,今天要給大家講的是Floyd算法。在那之前,大家還記得我們上一章講的內容嗎,就是那個Dijkstra算法,用來解決從A點到B點的最短路徑問題。我們還給出了Matlab代碼。Floyd算法也是用來處理最短路徑問題的。它的理念跟Dijkstra有點不一樣,但是最終的結果是一樣的。Floyd算法主要是用到了動態規划的思想。在這里博主不打算講到很抽象很高深的東西(畢竟博主也不是專業的),僅僅通過比較通俗易懂的方式來給大家講解這個算法的思想(如果有問題大家幫忙指出來哈)。本文的圖片和思想,借用了https://blog.csdn.net/qq_34374664/article/details/52261672的博文(圖片畫得好好,有誰知道是用什么軟件畫的嗎,博主也想學一學)。本篇的主要思想來自那篇博文,因此會有很多類似的,但博主還是想以自己的理解來解釋Floyd算法的理念。好了我們開始吧...
二、Floyd算法
首先,大家看上面的圖,暑假,小哼准備去一些城市旅游。有些城市之間有公路,有些城市之間則沒有。為了節省經費以及方便計划旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。我們用1-4來表示4個地點,並用箭頭和箭頭上的數字來表示一個地點到另一個地點的距離(注意,有些路是單向的)。這樣就得到下圖
現在,我們希望能求解出任意兩點的最短路徑及其距離。
好了,為了求解這個問題,我們先用一個二維的數組A來存儲我們圖的信息。如下圖(怎么看這個圖下面解釋)
這個是怎么數組填寫出來的呢,舉例來講吧,比如1號城市到2號城市的路程為2,則設A(1, 2)的值為2。2號城市無法到達4號城市,則設置A(2, 4)的值為$\infty$。另外此處約定一個城市自己是到自己的也是0,例如A(1, 1)為0。
現在問題是,如何求解任意兩個點的最短距離。我們可以這樣想,我們假設第$i$點和第$j$點的距離,應該就包括兩種情況:
1. $i$和$j$之間是直接相連的(即$i \rightarrow j$);
2. $i$和$j$之間還有其他端點(即$i \rightarrow \cdot \cdot \cdot \rightarrow j$);
上面兩句話什么意思呢,我們先看下面這張圖:
我們現在比如說從地點$i$到地點$j$,我們可以直接走紅色路線,即$i \rightarrow j$;或者,走經過1(或者2或者經過1和2)的路線。即從地點$i$開始,先經過其他地點,再從其他地點到$j$,即$i \rightarrow \cdot \cdot \cdot \rightarrow j$
那么,哪個才是最短距離呢。接下來就是算法的核心和重點了,大家注意啦!!
當任意兩點之間不允許經過第三個點時,這些城市之間最短路程就是初始路程,如下
(1)現在,如果我只允許經過1號頂點,求任意兩點之間的最短路程,該怎么求呢?
由於只允許經過1號頂點,那任意兩點的路線不外乎只有兩種,即:
1. $i \rightarrow 1 \rightarrow j$
2. $i \rightarrow j$
要求最短路程,只要比較這兩個路線距離的大小即可。就是:
即
A(i, j) = min [A(i, j), A(i, 1) + A(1, j)]
在只允許經過1號頂點的情況下,任意兩點之間的最短路程更新為:
通過上圖我們發現:在只通過1號頂點中轉的情況下,3號頂點到2號頂點(A(3, 2))、4號頂點到2號頂點(A(4, 2))以及4號頂點到3號頂點(A(4, 3))的路程都變短了。
(2)接下來繼續求在只允許經過1和2號兩個頂點的情況下任意兩點之間的最短路程。如何做呢?
可以寫出公式:A(i, j ) = A(i, 1) + A(1, 2) + A(2, j)
根據(1)我們已經求出A(i, 1) + A(1, 2) = min [A(i, 2), A(i, 1) + A(1, 2)]。
故我們只需要在只允許經過1號頂點時任意兩點的最短路程的結果下,再判斷如果經過2號頂點是否可以使得$i$號頂點到$j$號頂點之間的路程變得更短。
即
A(i, j) = min [A(i, j), A(i, 2) + A(2, j)]
在只允許經過1和2號頂點的情況下,任意兩點之間的最短路程更新為:


function [D, path] = floyd(A) % [D,PATH] = FLOYD(A) % returns the distance and path between the start node and the end node. % % A: adjcent matrix %% 初始化 %節點的數量n D = A; n = length(D); path = zeros(n, n); %% 初始化path for i = 1: n for j = 1: n if D(i, j) ~= inf path(i, j) = j; end end end %% 記錄最短路徑與最短距離 for k = 1: n for i = 1: n for j = 1: n if D(i, j) > D(i, k) + D(k, j) D(i, j) = D(i, k) + D(k, j); path(i, j) = path(i, k); end end end end