最短路徑:迪傑斯特拉算法保姆級別詳解

一,大致的遍歷過程圖解及過程講解

先從開始點尋找與其他邊連接最小的邊

1,如下圖(a)中,找A點與其它五點中C的距離最短弧;

       所以連接AC(因爲由圖可知B點無入度,所以可忽略不計);

2,圖(b)將與A點連接的頂點和與C點連接的所有頂點的弧相比較,看誰距離最短,

      (因爲此時D點不直接與A相連,而是通過中間點C,所以此時AD的距離可以看作AC+CD)

      所以連接AE。

3,圖(c)與A點連接的頂點和與C點連接的頂點和E點連接的所有頂點的弧相比較,看誰距離最短,

     此時A點到F點有兩條路:1,AF,2,通過E點再連接A->E->F.

     此時A點到D點也有兩條路:1,A->C->D;2,A->E->D;

     此時通過比較A->E->D最短。所以連接ED;

4,圖(d)與A點連接的頂點和與C點連接的頂點和E點連接的頂點和D點連接的所有頂點的弧相比較,看誰距離最短,
     此時A到F有三條路:1,A->F;

                                       2,A->E->F; 

                                       3,A->E->D->F

     根據比較長短可知第三種距離最短。所以連接DE。

(因爲B點沒有入度,所以AB之間無連接)

二,實現方法

這種方法除了構造鄰接矩陣所需的結構體和函數之外,加入了三個新數組:

int S[pointMax];         //到所求頂點的最短路徑是否被確定,等於-1代表未被確認

     即表示某一點是否被連接(如上圖a中,C點連接,則S[2]賦值爲1,代表該點已確認)

int D[pointMax];         //最短路徑

     即表示某點到所求點的距離(如上圖a中,C點確認連接,則D[2]賦值爲10,代表AC距離爲10)

int Path[pointMax];      //連通弧的前驅

     爲了防止出現迴路,即某一連通邊都賦值爲一樣,

    (如上圖c中,ED連接,此時A->E->D連接,所以A點E點D點的Path[]值一樣

 

第一步:先構造鄰接矩陣,並賦值,該過程類似於圖的鄰接矩陣儲存法類似。

第二步,先將上面新加入的三個數組進行賦值。

第三步:從所有能連通的弧中,找到一個最小弧,並連通,然後給相對應的三個數組進行賦值改變。

然後第三步繼續循環循環,總共循環(頂點數-1)次。

大致思路都已經在上面的圖中寫出來了,只要將上面的圖理解,大致就會了,三個數組只是輔助遍歷。

實現截圖

這個截圖顯示的信息並不是特別多(如果想知道詳細每一次遍歷後信息,可自行在對應地方添加顯示信息)

四,代碼

#include<iostream>
#include<stdlib.h>

using namespace std;

#define pointMax 100
#define MaxInt 32767

struct AMgroup
{
    char VTchart[pointMax];                  //頂點表
    int AMchart[pointMax][pointMax];         //鄰接矩陣
    int point, vert;                         //點,邊
};

int AMlocate(AMgroup A, char x)
{
    for (int i = 0; i < A.point; i++)        //依次輸入點的信息
    {
        if (A.VTchart[i] == x)
        {
            return i;
            break;
        }
    }
}

void CreatAM(AMgroup &A)
{
    cout << "輸入鄰接矩陣頂點數:";          //第一步
    cin >> A.point;
    cout << "輸入鄰接矩陣邊數:";
    cin >> A.vert;
    getchar();

    char a[100];
    cout << "輸入點的信息:";                //第二步
    gets_s(a);
    for (int i = 0; i < A.point; i++)        //依次輸入點的信息
    {
        A.VTchart[i] = a[i];
    }
    for (int i = 0; i < A.point; i++)        //初始換鄰接矩陣,邊的權值均設爲最大
    {
        for (int j = 0; j < A.point; j++)
        {
            A.AMchart[i][j] = MaxInt;
        }
    }

    cout << endl;
    char v1, v2; int len;
    for (int i = 1; i <= A.vert; i++)        //構造鄰接矩陣
    {
        cout << "輸入第" << i << "條邊的兩個頂點以及權值:";
        cin >> v1 >> v2 >> len;
        int m, n;
        m = AMlocate(A, v1);
        n = AMlocate(A, v2);
        A.AMchart[m][n]=len;
    }
}

int S[pointMax];         //到所求頂點的最短路徑是否被確定,等於-1代表未被確認
int D[pointMax];         //最短路徑
int Path[pointMax];      //連通弧的前驅
void SP_DIJ(AMgroup &A, int v0)
{
    //初始化過程
    int number = A.point;                     //有向圖中的頂點數
    for (int i = 0; i < number; i++)
    {
        S[i] = -1;                         //初始爲空-1
        D[i] = A.AMchart[v0][i];           //各個頂點到v0的權值
        if (D[i] < MaxInt)
        {
            Path[i] = v0;                  //如果有邊,則將i的前驅初始化爲v0
        }
        else
        {
            Path[i] = -1;                  //無邊則初始化爲空-1
        }
    }
    S[v0] = 1;             //將v0加入S中
    D[v0] = 0;             //源點到源點的距離爲0
    //求最短路徑
    int n;
    for (int i = 1; i < number; i++)//對其餘number-1個頂點依次進行計算
    {
        int min = MaxInt;
        for (int j = 0; j < number; j++)
        {
            if (S[j] == -1 && D[j] < min)
            {
                n = j;
                min = D[j];
            }
        }
        cout << n << ":" << min << endl;
        S[n] = 1;
        for (int j = 0; j < number; j++)
        {
            if (S[j] == -1 && D[n] + A.AMchart[n][j] < D[j])
            {
                D[j] = D[n] + A.AMchart[n][j];
                Path[j] = n;
            }
        }
    }
    cout << endl;
    for (int i = 0; i < A.point; i++)
    {
        if (i != v0)
        {
            if (D[i] == MaxInt)
            {
                cout << A.VTchart[v0] << "-->" << A.VTchart[i] << "不連通" << endl;
            }
            else
            {
                cout << A.VTchart[v0] << "-->" << A.VTchart[i] << "的最短路徑爲:" << D[i] << endl;
            }
        }
    }
}

int main()
{
    AMgroup *A = new AMgroup;
    CreatAM(*A);
    int m;
    cout << "\n從第幾個點開始遍歷:";
    cin >> m;
    SP_DIJ(*A, m);
    system("pause");
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章