貪心策略之Dijkstra算法

Dijkstra算法是解決有向帶權圖中最短路徑的算法。

我用自己的語言解釋Dijkstra算法的過程:

1.首先有一個有向帶權圖G=(V,E),V爲頂點集合,E爲邊集合,用鄰接矩陣map[n][n]來儲存。

    確定一個起始點origin,有一個輔助集合s,一開始將origin併入s中。

    有一個輔助數組dist[n],dist[i]表示i距離origin的最短距離,初始化dist[i]=map[origin][i]。若不存在弧則相應等於無窮大

2.找一個頂點j,使頂點j存在於V-s中(即頂點j屬於V但不屬於s),並且dist[j]是所有V-s頂點中最小的一個,將頂點j併入s中;

3.遍歷以頂點j爲地點的弧<j,k>且k屬於V-s中,如果dist[k] > dist[j] + weight<j,k>,則令dist[k]=dist[j] + weight<j,k>;

    這一步相當於搭一個頂點j的順風車。已知origin-j最短的距離是dist[j],若origin-k的(直接)距離大於

    dist[j] + weight<j,k>,說明源點到頂點k的路徑可以通過頂點j這條路而減少距離。

4.重複2,3步,直到s中包含了V中所有的頂點,結束算法。


代碼:(C++實現)

#include <iostream>
#define MAX 999999
using namespace std;

const int n =5;          //頂點數量
int map[n+1][n+1];       //有向圖 鄰接矩陣
int dist[n+1]={MAX};     //起點到其餘頂點的距離
int s[n+1]={0};          //頂點集合
int pre[n+1]={0};        //每個頂點的直接前驅


void findMin(int origin)
{
    int i,j;
    for(j=1;j<=n;j++)
    {
        int minWeight=MAX;      //dist[i]中最小權值
        int minPoint =0;        //最小權值的點
        for(i=1;i<=n;i++)
        {
            if( !s[i] && dist[i]<= minWeight ) //尋找不在s中的最小權值的點
            {
                minWeight = dist[i];
                minPoint = i;
            }
        }
        if(minPoint==0)         //如果沒有找到,說明所有頂點都以併入s中
            return ;
        s[minPoint]=1;                         //將最小權值的點並中s中
        //修改不在s中的其他頂點的dist值
        for(i=1;i<=n;i++)
        {
            if( !s[i] && map[minPoint][i] != MAX)
                if(dist[i] > dist[minPoint] + map[minPoint][i])
                {
                    dist[i] = dist[minPoint] + map[minPoint][i];
                    pre[i] = minPoint;  //將需要修改的頂點的直接前驅改爲最小的權值點
                }
        }
    }

}

void findPath(int i)
{
    if(pre[i]==0)   //表示i可能是起始點,也可能是和起始點不強連通的的點
    {
        if(dist[i] != MAX)  //起始點
            cout<<i;
        else                //與起始點不強連通的點
            cout<<"不存在";
        return ;
    }
    findPath(pre[i]);
    cout<<"-"<<i;

}

int main()
{
    int i,j;
    int weight;
    int origin;              //起點頂點


    //鄰接矩陣初始化
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            map[i][j] = MAX;

    cout<<"請輸入權值"<<endl;
    cout<<"格式:i j weight"<<endl;
    cout<<"示例:1 2 2  即有一條弧<1,2>,權值爲2,未輸入數據則默認爲無窮大"<<endl;
    cout<<"結束時輸入 0 0 0"<<endl;
    cout<<"*************************"<<endl;
    while(1)
    {
        cin>>i>>j>>weight;
        if(i==0 && j==0 && weight==0)
            break;
        else
            map[i][j] = weight;
    }

    cout<<"請輸入起始點"<<endl;
    cin>>origin;
    //也可以通過遍歷鄰接矩陣找到入度爲0的點找到源點
    map[origin][origin]=0;

    /*初始化dist[]與pre[]
     *dist[]初始值爲源點與其餘頂點i的權值,即map[origin][i],不存在弧則爲無窮大MAX
     *pre[] 中,若其餘頂點i與源點有弧,則pre[i]=1,否則等於0
     */
    for(i=1;i<=n;i++)
    {
        dist[i]=map[origin][i];
        if(map[origin][i] != MAX && map[origin][i] != 0)
            pre[i]=origin;
    }
    s[origin]=1;//初始化s[],即將源點加入s中
    findMin(origin);

    /*輸出頂點的頂點的最短路徑*/
    for(i=1;i<=n;i++)
    {
        cout<<"從起點"<<origin<<"去頂點"<<i<<"的最短路徑爲:";
        findPath(i);
        cout<<" 最短距離爲:"<<dist[i];
        cout<<endl;
    }

    return 0;
}

實現示例:

例子1:


例子2:


發佈了112 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章