關於dijkstra算法的一點理解


  最近在准備ccf,各種補算法,圖的算法基本差不多看了一遍。今天看的是Dijkstra算法,這個算法有點難理解,如果不深入想的話想要搞明白還是不容易的。弄了一個晚自習,先看書大致明白了原理,就根據書上的代碼敲,邊敲邊深入思考,第一遍敲完運行失敗,然后回過頭在分析代碼,改進還是失敗。經過三次修改總算勉強跑起來了,但是結果還是不對,找了半天也找不出來。感覺整個人都不好了,弄了快三個小時結果還是有問題。時間差不多就回宿舍,在路上邊走邊想終於找到自己代碼的問題了,回到宿舍代碼修改后終於完美運行。經過一晚上的不斷思考深入,反復推敲,得到了完美結果,付出和回報是成正比的。

  好了!大致講一下自己對這個算法的理解吧!首先要想弄明白這個算法還是得了解一下廣度優先搜索的原理,這個算法就是基於廣搜的原理得出來的一個算法。算法的核心又有點貪心算法的味道,所以說這個算法相當經典。Dijkstra算法是求單個節點到圖中其他所有節點的最短距離,為了解決這個問題,首先要引入三個數組D[i](記錄起始點到其他各點的最短距離),mark[i](表示每個節點的是否已經訪問過),p[i](記錄每個節點的前驅結點,便於觀察最后到各個頂點的路徑)。

  Dijkstra算法的執行步驟:1.先初始化D[i]=v與i之間的距離(若兩點不相連則為INIFY),mark[i]=0,p[i]=0,並將起始節點v的mark[v]=0;

              2.遍歷剩余的節點,找出剩余節點與v之間的距離(初始狀態下除去相連的節點間有距離外其余所有節點間距離為INIFY),不相連的節點依然設為INIFY不變。找出其中與v距離最小的那個點k,mark[k]=1;

               3.遍歷所有節點,對其中mark[i]==0的點與k點的距離+2中的那個最小距離與D[i]比較,若小於D[i]則更新D[i],並將p[i]標記為k(k為該節點的前驅)。

             4.遍歷完后得到的D[i]就是v到各個節點的最短距離.

 

#include<iostream>

using namespace std;
#define INFTY 10000

class Graph
{
public:
    Graph(int n);        //構造函數初始化 
    ~Graph();            //析構函數銷毀 
    void SetEdge(int v1,int v2,int weight);        //設置圖中的相連邊及其權值
    void Dijkstra(int v0);        //迪傑斯特拉算法 
    void Print(); 
private:
    int numVex;            //頂點數 
    int numEdge;        //邊數 
    int **matrix;        //
    int *mark;            //頂點標記 
    int *p;                //表示PathMatrix最短路徑的前驅結點 
    int *D;                //表示ShortPathTa即兩點間的帶權長度 
};

Graph::Graph(int n)
{
    numVex=n;
    numEdge=0;
    mark=new int[numVex];
    p=new int[numVex];
    D=new int[numVex]; 
    matrix=new int*[numVex];
    for(int i=0;i<numVex;i++)
    {
        matrix[i]=new int[numVex];
    }
    for(int i=0;i<numVex;i++)
    {
        mark[i]=0;
        p[i]=0;
        D[i]=0;
    }
    for(int i=0;i<numVex;i++)
    {
        for(int j=0;j<numVex;j++)
        {
            matrix[i][j]=matrix[j][i]=INFTY;
        }
    }
} 

Graph::~Graph()
{
    delete []p;
    delete []D;
    delete []mark;
    for(int i=0;i<numVex;i++)
    {
        delete []matrix[i];
    }
    delete []matrix;
}

void Graph::SetEdge(int v1,int v2,int weight)
{
    matrix[v1][v2]=matrix[v2][v1]=weight;
}

void Graph::Dijkstra(int v0)
{
    int k,min;
    for(int i=0;i<numVex;i++)
    {
        D[i]=matrix[v0][i];
    }
    D[v0]=0;     
    mark[v0]=1;        //表示已經求得v0點的最短路徑 
    for(int i=1;i<numVex;i++)
    {
        min=INFTY;
        for(int j=0;j<numVex;j++)
        {
            if(!mark[j] && D[j]<min)
            {
                k=j;
                min=D[j];
            }
        }
        mark[k]=1;    //表示從v0到k已經找到最短路徑 

        //修正目前的最短路徑 
        for(int j=0;j<numVex;j++)
        {
            if(!mark[j] && (min+matrix[k][j]<D[j]))
            {
                D[j]=min+matrix[k][j];    //修改當前路徑的長度 
                p[j]=k;            //存放當前節點的前驅 
            }
        }
    }
}

void Graph::Print()
{
    cout<<"v0到各頂點的最短距離:"<<endl;
    for(int i=0;i<numVex;i++)
    {    
        cout<<D[i]<<" ";
    }
    cout<<endl;
    cout<<"各頂點的前驅頂點:"<<endl;
    for(int i=0;i<numVex;i++)
    {    
        cout<<p[i]<<" ";
    }
}

int main()
{
    int n,m,t;
    cout<<"請輸入頂點數n和邊數m"<<endl;
    cin>>n>>m;
    Graph G(n);
    int v1,v2,weight;
    cout<<"請輸入頂點v1,v2及兩頂點間邊的權值"<<endl;
    for(int i=0;i<m;i++)
    {
        cin>>v1>>v2>>weight;
        G.SetEdge(v1,v2,weight);
    }
    cout<<"請輸入迪傑斯特拉算法的起始頂點"<<endl;
    cin>>t; 
    G.Dijkstra(t);
    G.Print();
    
    return 0;
}

  代碼自己寫的,可以完美運行!希望對大家有幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM