單源最短路徑——Dijkstra算法

原理解析

http://blog.csdn.net/wizard_wsq/article/details/51095853

小技巧總結

圖用鄰接矩陣表示
Distance[i]表示v0到頂點i的距離
int prev[i]表示節點v0到節點i存在最短路徑時,其前一個節點。

Dijkstra代碼

//Dijkstra算法函數,求給定頂點到其餘各點的最短路徑
//參數:鄰接矩陣、出發點的下標、結果數組、路徑前一點記錄
//Graph[][N],表示加權有向圖的鄰接矩陣,其中Graph[i][j]=M=65536,表示i到j不可直接到達
//v0表示以v0頂點開始尋找到其他頂點的距離
//Distance[i]表示v0到頂點i的距離
//prev[]表示
void Dijkstra(int Graph[][N], int v0, int Distance[], int prev[])
{
    bool visited[N];//表示是否已經訪問過

    int i, j, u;
    //初始化
    for (int i = 0; i<N; i++)
    {
        Distance[i] = Graph[v0][i];//包含了Distance[v0] = 0;
        visited[i] = 0;
        if (Distance[i] == M)
            prev[i] = -1;
        else
            prev[i] = v0;
    }
    visited[v0] = 1;       

    for (i = 1; i < N; i++)//每循環一次,求得一個最短路徑
    {
        int mindis=M, dis;//在當前還未找到最短路徑的頂點中,尋找具有最短距離的頂點
        u = v0;
        for (j = 0; j < N; j++) //求離出發點最近的頂點
            if (visited[j] == 0 && Distance[j]<mindis)
            {
                mindis = Distance[j];
                u = j;
            } 
        visited[u] = 1;
        for (j = 0; j<N; j++) //由於新增了頂點u,所以要更新每個未被訪問的頂點的distance。只會由u來影響
            if (visited[j] == 0 && Graph[u][j]<M)
            { //對還未求得最短路徑的頂點。求出由最近的頂點 直達各頂點的距離
                dis = Distance[u] + Graph[u][j];
                // 如果新的路徑更短,就替換掉原路徑
                if (Distance[j] > dis)
                {
                    Distance[j] = dis;
                    prev[j] = u;
                }
            } // if 語句體結束,j循環結束
    } // i循環結束
}

Test代碼

#pragma once
#include<iostream>
#include <cstdio>
#include <list>
#include <vector>
#include <queue>
#include<stack>
#include<fstream>

#define M   65535 //無窮大
#define N   5 //頂點數
//Dijkstra算法函數,求給定頂點到其餘各點的最短路徑
//參數:鄰接矩陣、出發點的下標、結果數組、路徑前一點記錄
//Graph[][N],表示加權有向圖的鄰接矩陣,其中Graph[i][j]=M=65536,表示i到j不可直接到達
//v0表示以v0頂點開始尋找到其他頂點的距離
//Distance[i]表示v0到頂點i的距離
//prev[]表示
void Dijkstra(int Graph[][N], int v0, int Distance[], int prev[])
{
    bool visited[N];//表示是否已經訪問過

    int i, j, u;
    //初始化
    for (int i = 0; i<N; i++)
    {
        Distance[i] = Graph[v0][i];//包含了Distance[v0] = 0;
        visited[i] = 0;
        if (Distance[i] == M)
            prev[i] = -1;
        else
            prev[i] = v0;
    }
    visited[v0] = 1;       

    for (i = 1; i < N; i++)//每循環一次,求得一個最短路徑
    {
        int mindis=M, dis;//在當前還未找到最短路徑的頂點中,尋找具有最短距離的頂點
        u = v0;
        for (j = 0; j < N; j++) //求離出發點最近的頂點
            if (visited[j] == 0 && Distance[j]<mindis)
            {
                mindis = Distance[j];
                u = j;
            } 
        visited[u] = 1;
        for (j = 0; j<N; j++) //由於新增了頂點u,所以要更新每個未被訪問的頂點的distance。只會由u來影響
            if (visited[j] == 0 && Graph[u][j]<M)
            { //對還未求得最短路徑的頂點。求出由最近的頂點 直達各頂點的距離
                dis = Distance[u] + Graph[u][j];
                // 如果新的路徑更短,就替換掉原路徑
                if (Distance[j] > dis)
                {
                    Distance[j] = dis;
                    prev[j] = u;
                }
            } // if 語句體結束,j循環結束
    } // i循環結束
}
// 參數:路徑前一點記錄、出發點的下標、到達點下標
void PrintPrev(int prev[], int v0, int vn)
{
    int tmp = vn;
    int i, j;
    //臨時存路徑
    int tmpprv[N];
    //初始化數組
    for (i = 0; i < N; i++)
        tmpprv[i] = 0;
    //記錄到達點下標
    tmpprv[0] = vn + 1;
    //中間點用循環記錄
    for (i = 0, j = 1; j < N; j++)
    {
        if (prev[tmp] != -1 && tmp != 0)
        {
            tmpprv[i] = prev[tmp] + 1;
            tmp = prev[tmp];
            i++;
        }
        else break;
    }

    //輸出路徑,數組逆向輸出
    for (i = N - 1; i >= 0; i--)
    {
        if (tmpprv[i] != 0)
        { //排除0元素
            printf("V%d", tmpprv[i]);
            if (i)  //不是最後一個輸出符號 
                printf("-->");
        }
    }
    printf("-->V%d", vn + 1);
}

//主函數
void test_dijkstra()
{
    //給出有向網的頂點數組
    char *Vertex[N] = { "V1", "V2", "V3", "V4", "V5" };
    //給出有向網的鄰接矩陣
    int Graph[N][N] = {
        { 0, 10, M, 30, 100 },
        { M, 0, 50, M, M },
        { M, M, 0, M, 10 },
        { M, M, 20, 0, 60 },
        { M, M, M, M, 0 },
    };
    int Distance[N]; //存放求得的最短路徑長度
    int prev[N];  //存放求得的最短路徑
    int i;
    //調用Dijkstra算法函數,求頂點V1到其餘各點的最短路徑
    //參數:鄰接矩陣、出發點的下標、結果數組、路徑前一點記錄
    Dijkstra(Graph, 0, Distance, prev);
    for (i = 0; i < N; i++)
    {
        //輸出最短路徑長度
        cout << Vertex[0] << " " << Vertex[i] << " " << Distance[i]<<" ";
        //printf("%visited-->%visited:%d\t", Vertex[0], Vertex[i], Distance[i]);
        //輸出最短路徑
        PrintPrev(prev, 0, i);
        printf("\n");
    }
}
發佈了159 篇原創文章 · 獲贊 481 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章