1. 程式人生 > >數學建模法-Dijkstra算法

數學建模法-Dijkstra算法

span amp end 我會 -s block 分享 http 我們

一、引言

哈嘍大家好,今天要講的是圖論中的一個經典的算法。是一種叫Dijkstra算法的東東。這個算法是幹什麽用的呢。首先大家先看下面這幅圖:

技術分享圖片

這個東西是什麽呢。我們可以這樣理解,假如AF表示6地點。那些連接線就是道路。連接線上的數字就是兩個地點間的距離。這樣講是不是很直觀呢。好了,假如博主家在A點,博主的女神家在F點,有一天博主想去女神家,就有很多條路線可以走。可是博主很懶誒,肯定就想走最短的路線。那麽,怎麽才能很快的就求解出最短的路線呢。Dijkstra算法就是用來解決這樣的問題的。

二、Dijkstra算法的思想

Dijkstra

算法的思想其實很直觀,就是我從A點出發,發現可以走的路就只有CB了,那麽我肯定就要走最近的那條路,也就是C(同時記錄CA的距離)。接下來,我們從C點出發,可以走的路有BDE,再選擇出最近的一條路,也就是B點(同時也記錄CB的距離)。通過每次不斷的走最短的路線。最後走到F的路線也肯定是最短的。這就是Dijkstra算法的思想。當然講起來很簡單,計算起來有時候也會遇到一些其他因素。接下來我會盡可能通俗易懂的講這個算法的過程講清楚。

三、Dijkstra算法步驟

接下來的講解, 可能有點生澀,我會先寫出來再慢慢解釋。

首先,我們要先確定我們的起點。在這裏我們定我們的起點為A

。但這樣還不夠,我們要寫成(端點,端點與起點之間的距離)的形式。因此,我們的A就要寫為(A, 0)。

準備工作做完了,我們開始吧。

(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最後一列填完。那我們就找到了最短去博主女神家的路了。

技術分享圖片

現在,我們知道從AF的最短路線和距離分別是A-C-B-D-F10。現在我們要談談Box3,當我們完成這個表後,我們不僅可以馬上知道博主家到博主女神家的最短路線。還能知道任意點到起點的最短路線呢。比如說,我們想知從AE的最短路線。看Box3,E的上一點是D,D的上一點是B,B的上一點是C,C的上一點是A。這樣就得到A-C-B-D-E是最短路線。而Box3中E最下方的7就表示最短距離值哦。現在你們是不是搞懂了呢~^_^。

四、DijkstraMatlab實現

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];        

然後,因為我們要算AF的最短距離,因此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算法