數學建模法-Dijkstra算法
一、引言
哈嘍大家好,今天要講的是圖論中的一個經典的算法。是一種叫Dijkstra算法的東東。這個算法是幹什麽用的呢。首先大家先看下面這幅圖:
這個東西是什麽呢。我們可以這樣理解,假如A到F表示6個地點。那些連接線就是道路。連接線上的數字就是兩個地點間的距離。這樣講是不是很直觀呢。好了,假如博主家在A點,博主的女神家在F點,有一天博主想去女神家,就有很多條路線可以走。可是博主很懶誒,肯定就想走最短的路線。那麽,怎麽才能很快的就求解出最短的路線呢。Dijkstra算法就是用來解決這樣的問題的。
二、Dijkstra算法的思想
Dijkstra
三、Dijkstra算法步驟
接下來的講解, 可能有點生澀,我會先寫出來再慢慢解釋。
首先,我們要先確定我們的起點。在這裏我們定我們的起點為A
準備工作做完了,我們開始吧。
(1) 首先從(A, 0)開始,A端點所連接的兩個點分別是(B, 5)和(C, 1)。我們先把(B, 5)和(C, 1)存到Box裏,並且根據大小來排序(最小排左邊)。如下圖
顯然,(C, 1)是最小的,因此,A點到下一個點的最短路線點是(C, 1)。我們不妨再創建一個Box吧,稱之為Box3吧。稱Box3是因為有3行。第一行表示圖上所有的地點,第二行表示對於第一行地點的前一個最短路線點,第三行表示第一行的地點與原點的距離。如下:
大家可以看到, 第二行第一列,因為我們的A就是起點,在A之前並沒有什麽點,因此打×,下面的0表示無的意思。因為我們現在求出我們的(C, 1)是我們的下一個最短路線點,並且C是從A走過去的,故第二行第三列是A ,其下面的1表示從起點到C的最短距離為1。
(2) 好了,現在,既然確定了(A, 0)的下一個點是(C, 1)。接下來,我們要從(C, 1)出發,我們看看,跟(C, 1)連接的點有(B, 3)點(註意,是3不是2,我們說過是與起點的距離,即A-C-B)和(D, 5)點以及(E, 9)。把其填入Box裏面並排序。如下:
咦,這時候你可能會有疑問,為什麽(C, 1)不見了,而且有兩個B,一個是(B, 3)一個是(B, 5)。別急,我正要講。當我們確定好最短距離的點後,我們就將其從Box裏面剔除掉,因為C已經被用過了。而至於為何有兩個B。大家還記得,當我們直接從A到B的時候,距離是5;而當我們從A到C到B的時候,距離是3。因此就有兩個了。現在,在這個Box裏面我們找到最小的數,就是(B, 3)。這樣我們就可以在Box3也填入我們的數,如下:
(3) 好的,讓我們繼續,接下來我們從(B, 3)開始,由於B的連接點只剩(D, 4)(已經用過的點不能再用,故A和C不算。畢竟我們肯定不走回頭路呀hhh)。填入Box並排序,可以得到(D, 4)是最小的數,填入Box3中。如下
(4) 好了,接下來我們從(D, 4)出發,跟(D, 4)連接的有(E, 7)和(F, 10),填入Box並排序,可以得到(E, 7)是最小的數,填入Box3中。如下:
(5) 好,接下來我們從(E, 7)出發,誒這時候發現,E已經沒有可連接的點了。那Box裏面只剩(F, 10)了。把Box3最後一列填完。那我們就找到了最短去博主女神家的路了。
現在,我們知道從A到F的最短路線和距離分別是A-C-B-D-F和10。現在我們要談談Box3,當我們完成這個表後,我們不僅可以馬上知道博主家到博主女神家的最短路線。還能知道任意點到起點的最短路線呢。比如說,我們想知從A到E的最短路線。看Box3,E的上一點是D,D的上一點是B,B的上一點是C,C的上一點是A。這樣就得到A-C-B-D-E是最短路線。而Box3中E最下方的7就表示最短距離值哦。現在你們是不是搞懂了呢~^_^。
四、Dijkstra的Matlab實現
function [distance, path] = dijkstra(A, sn, en) % [DISTANCE,PATH] = DIJKSTRA(A, SN, EN) % returns the distance and path between the start node and the end node. % % A: adjcent matrix % sn: start node % en: end node %% 初始化 %節點的數量n n = length(A); %以sn為起點的矩陣(distance vector) D = A(sn,:); vi = ones(1, n); %讓節點都可見 vi(sn) = 0; %起點節點是不可見的 %parent:即Box3中的第二行 parent = zeros(1, n); %% 計算最短距離 for i = 1: n-1 temp = zeros(1, n); count = 0; %把distance vector裏面非頂點的距離值放進temp,以便後續比大小取出最短距離 for j = 1: n if(vi(j)) temp = [temp(1: count) D(j)]; else temp = [temp(1: count) inf]; end count = count + 1; end %找出最短距離的點,並設定為下次路徑的頂點 [~, index] = min(temp); vi(index) = 0;%讓頂點不可見 for k = 1: n if A(index, k) + D(index) < D(k) D(k) = A(index, k) + D(index); parent(k) = index; %算出k的上一層最短路徑點,即Index end end end %%叠代完成後,distance矩陣的數值都是相對應的最短距離 distance = D(en); %%求出最短路徑 path = []; t = en; path(1) = t; count = 1; while t ~= sn && t > 0 p = parent(t); path = [p path(1:count)]; %從path裏面 不斷往左邊放路徑點,最右邊是終點 t = p; count = count + 1; end path(1) = sn; path = path(1: count);
驗證一下,我們根據這篇的圖例寫出鄰接矩陣(這裏我當大家知道什麽是鄰接矩陣,不知道的自己百度一下哈)。得到如下:
A = [0 5 1 5 9 inf; 5 0 2 1 inf inf; 1 2 0 4 8 inf; inf 1 4 0 3 6; inf inf 8 3 0 inf; inf inf inf 6 inf 0];
然後,因為我們要算A到F的最短距離,因此sn = 1, en = 6。故在matlab中輸入:
[distance, path]=dijkstra(A, 1, 6)
最後就得到如下結果:
distance = 10 path = 1 3 2 4 6
1-3-2-4-6翻譯過來也就是A-C-B-D-F。跟我們前面分析的一致。故正確。
數學建模法-Dijkstra算法