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

最短路徑-Dijkstra(迪傑斯特拉)演算法

  • 最短路徑-Dijkstra(迪傑斯特拉)演算法


  • 網圖的最短路:

最短路徑,是指兩頂點之間經過的邊上權值之和最小的路徑,並且我們稱路徑的第一個頂點是源點,最後一個頂點是終點

  • Dijkstra(迪傑斯特拉)演算法:

概況:

按路徑長度遞增的次序產生的最短路徑演算法,通過一步步計算出路徑之間頂點的最短路徑,在此過程中都是基於已經求出的最短路徑基礎上,求得更遠頂點的最短路徑

思想:

當前已經求得的最短路徑邊集為{MT}當前最短路終點與相連點(不在MT中)的距離(與起點距離)集合為{WP}

每次都在WP中取與當前終點最近的一個點,將最短邊L加入最短路徑集{MT},記此時新的終點為NewEnd

掃描不在最短路徑中的所有點,如果 NewEnd+L<Dis(表示起點到當前掃描點的距離),更新最短路

相似演算法:

在最小生成樹上用過類似思想,只不過最小生成樹要求全部點都要連通

留個傳送門:最小生成樹-Prim(普里姆)演算法

圖解:

兩個工具:

a.Path[MAX_SIZE]:記錄路徑,Path[i]是i的前驅,路徑方向  Path[i] -> i

b.Short_Path[MAX_SIZE]:Short_Path[i] 表示 從起點Start(不一定是0或者1)到 i 的最短路徑大小

以下圖為慄,v0為起點

 

首先記錄下v0到相連點的距離(明顯是v1和v2),進行初始化,此時:

Path:{ 0 0 0 0 0 0 0 0 0 } --- 初始化0

Short_Path:{ 0 1 5 65535 65535 65535 65535 65535 65535 } --- v0與v1距離為1,v0與v2距離為5

選出最短Short_Path 中的最短距,v1成為新的最短路終點,如下圖,此時v1與v2,v3,v4相連

所有v0-v3=1+7=8 .......,可得(掃描更新後):

Path:{ 0 0 1 1 1 0 0 0 0 } 

Short_Path:{ 0 1 4 8 6 65535 65535 65535 65535

 一樣,選出Short_Path中此時沒有加入最短路頂點的最短路(紅色),也就是4,得到 v0-v1-v2 ,v2為最短路新頂點

繼續更新最短路,加入v4,v5,很明顯,v0-v1-v4=6,而v0-v2-v4=5,路徑更新為後者

Path:{ 0 0 1 1 2 2 0 0 0 } 

Short_Path:{ 0 1 4 8 5 11 65535 65535 65535

此時沒有加入最短路的最小路徑為5,也就是v4作為新終點

按之前步驟繼續往下走,直到v8:

Path:{ 0 0 1 4 2 4 3 6 7 } 

Short_Path:{ 0 1 4 7 5 8 10 12 16 } 

如下圖,得到最短路徑:v0-v1-v2-v4-v3-v6-v7-v8,最短路長度為16

 Short_Path的利用:

Short_Path 顯然是每一次最短路徑的延申,所以求得Start-End的最短路,同理,Start到任意點的最短路都可以在Short_Path 中查得

演算法複雜度:

             O(n^2)

  • Dijkstra模板:

#include <iostream>
#include<memory.h>
using namespace std;
#define MAX_SIZE 1024
#define INF 65535

//鄰接圖
struct MGrapth
{
    int Vexs[MAX_SIZE];  //頂點表
    int Arc[MAX_SIZE][MAX_SIZE];  //鄰接矩陣
    int Num_Vertext,Num_Edges;  //頂點數,邊數
};
MGrapth Map;

int Path[MAX_SIZE];   /*表示路徑 Path[i]->i*/
int Short_Path[MAX_SIZE]; /*Start->i 的最短路徑和*/
bool Vis[MAX_SIZE];   /*當前最短路徑結點true*/
int Res;  /*最短路*/

void Init(int n,int m)
{
    Res=0;
    memset(Vis,0,sizeof(Vis));
    memset(Path,0,sizeof(Path));
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
            Map.Arc[i][j]=INF;
    Map.Num_Vertext=n;
    Map.Num_Edges=m;
}

void Dijkstra(int Start)
{
    int v,w,k,Min;
    for(v=0;v<Map.Num_Vertext;v++)
        Short_Path[v]=Map.Arc[Start][v];  /*Start到相連結點的距離*/

    Short_Path[Start]=0;   /*Start->Start 的距離為0*/
    Vis[Start]=1;   /*Start為當前最短路徑結點*/

    for(v=1;v<Map.Num_Vertext;v++)
    {
        Min=INF;
        for(w=0;w<Map.Num_Vertext;w++)
        {
            if(!Vis[w]&&Short_Path[w]<Min)
            {
                k=w;
                Min=Short_Path[w];
            }
        }
        Vis[k]=true; /*找出最短路到散點的最小值,將該散點連入最短路*/

        for(w=0;w<Map.Num_Vertext;w++)  /*更新最短路*/
        {
            if(!Vis[w]&&Min+Map.Arc[k][w]<Short_Path[w])  /*圖中某點到v0的距離比當前路短,更新*/
            {
                Short_Path[w]=Min+Map.Arc[k][w];
                Path[w]=k;
            }
        }
    }
}