1. 程式人生 > >最短路徑問題---迪傑斯特拉(dijkstra)演算法

最短路徑問題---迪傑斯特拉(dijkstra)演算法

理解最短路徑——迪傑斯特拉(dijkstra)演算法

1.       迪傑斯特拉演算法簡介

 迪傑斯特拉(dijkstra)演算法是典型的用來解決最短路徑的演算法,也是很多教程中的範例,由荷蘭電腦科學家狄克斯特拉於1959年提出,用來求得從起始點到其他所有點最短路徑。該演算法採用了貪心的思想,每次都查詢與該點距離最近的點,也因為這樣,它不能用來解決存在負權邊的圖。解決的問題大多是這樣的:有一個無向圖G(V,E),邊E[i]的權值為W[i],找出V[0]到V[i]的最短路徑。

3.     迪傑斯特拉演算法的原理

迪傑斯特拉演算法實現動畫①首先,引入一個輔助向量D,它的每個分量D[i]表示當前所找到的 Dijkstra演算法執行動畫過程 Dijkstra演算法執行動畫過程 從起始點 (即源點 )到其它每個頂點 的長度。例如,D[3] = 2表示從起始點到頂點3的路徑相對最小長度為2。這裡強調相對就是說在演算法執行過程中D的值是在不斷逼近最終結果但在過程中不一定就等於長度。

②D的初始狀態為:若從v 到v[i]有弧(即從v到v[i]存在連線邊),則D[i]為弧上的權值(即為從v到v[i]的邊的權值);否則置D[i]為∞。顯然,長度為 D[j]= Min{ D |v[i]∈V } 的路徑就是從v出發到頂點v[j]的長度最短的一條路徑,此路徑為(v,v[j])。

③那麼,下一條長度次短的是哪一條呢?也就是找到從源點v到下一個頂點的最短路徑長度所對應的頂點,且這條最短路徑長度僅次於從源點v到頂點v[j]的最短路徑長度。 假設該次短路徑的終點是v[k],則可想而知,這條路徑要麼是(v,v[k]),或者是(v,v[j],v[k])。它的長度或者是從v到v[k]的弧上的權值,或者是D[j]加上從v[j]到v[k]的弧上的權值。

④一般情況下,假設S為已求得的從源點v出發的最短路徑長度的頂點的集合,則可證明:下一條次最短路徑(設其終點為x)要麼是弧(v,x),或者是從源點v出發的中間只經過S中的頂點而最後到達頂點 的路徑。 因此,下一條長度次短的的最短路徑長度必是D[j]= Min{ D[i] |v[i]∈V-S },其中D 要麼是弧( v,v[i])上的權值,或者是D[i]( v[k]∈S)和弧(v[k] ,v[i] )上的權值之和。

3.     迪傑斯特拉演算法的實現過程

迪傑斯特拉演算法流程圖①先取一點v[0]作為起始點,初始化dis[i],d[i]的值為v[0]到其餘點v[i]的距離w[0][i],如果直接相鄰初始化為權值,否則初始化為無限大;

②將v[0]標記,vis[0] = 1(vis一開始初始化為0);

③找尋與v[0]相鄰的最近點v[k],將v[k]點記錄下來,v[k]與v[0]的距離記為min;

④把v[k]標記,vis[k]=1;

⑤查詢並比較,讓dis[j]與min+w[k][j]進行比較,判斷是直接v[0]連線v[j]短,還是經過v[k]連線v[j]更短,即dis[j]=MIN(dis[j],min+w[k][j]);

⑥繼續重複步驟③與步驟⑤,知道找出所有點為止。

4.    迪傑斯特拉的實現程式碼(C/C++)

C++
void dijkstra(int n)
{
    //初始化v[0]到v[i]的距離
    for(int i=1;i<=n;i++)
        dis[i] = w[0][i];                                       
    vis[0]=1;//標記v[0]點
    for(int i = 1; i <= n; i++)
    {
        //查詢最近點
        int min = INF,k = 0;
        for(int j = 0; j <= n; j++)
            if(!vis[j] && dis[j] < min)
                min = dis[j],k = j;
        vis[k] = 1;//標記查詢到的最近點
        //判斷是直接v[0]連線v[j]短,還是經過v[k]連線v[j]更短
        for(int j = 1; j <= n; j++)
            if(!vis[j] && min+w[k][j] < dis[j])
                d[j] = min+w[k][j];
    }
}
轉自http://ibupu.link/?id=29