单源点最短路径算法(dijkstra)

来源:互联网 发布:设a为3阶矩阵,|a|=2 编辑:程序博客网 时间:2024/06/08 09:27

问题描述:给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。


算法思想:Dijkstra提出了一个按路径长度递增的次序产生最短路径的算法。首先,引进一个辅助向量D,它的每个分量D[i]表示当前所找到的从源点v到每个终点vi的最短路径长度。它的初始状态为:若v到vi有弧,则D[i]为弧上的权值,否则D[i]为无穷大。显然,长度为:

    D[j] = Min{D[i] | vi 属于V} 

的路径就是从v出发的长度最短的一条路径。此路径为 (v, vi)。 那么,长度次短的路径是哪一条呢?假设该次短路径的终点是vk,则可以证明,这条路径或者是(v, vk),或者是(v, vj, vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。

一般情况下,假设S为已经求得最短路径的终点的集合,则可证明:下一条最短路径(假设其终点为x)或者是弧(v, x),或者是中间只经过S中的顶点而最后到达顶点x的路径。这可以用反证法来证明。假设此路径上有一个顶点不在S中,则说明存在一条终点不在S而长度比此路径短的路径。但是这是不可能的,因为我们是按路径长度递增的次序来产生最短路径的,长度比此路径短的所有路径均已产生,它们的终点必定在S中,假设不成立。


假设有向图如下:


求源点v0到其余各顶点的最短路径。


c++语言实现:

#include <iostream>using namespace std;const int MAX = 0x7fffffff;     //定义无穷大const int NUM_VERTEX = 6;       //图中节点个数// 图的邻接矩阵表示int g_graph[6][6] = {0,   MAX, 10,  MAX, 30,   100,                     MAX, 0,   5,   MAX, MAX,  MAX,                     MAX, MAX, 0,   50,  MAX,  MAX,                     MAX, MAX, MAX, 0,   MAX,  10,                     MAX, MAX, MAX, 20,  0,    60,                     MAX, MAX, MAX, MAX, MAX,  0};long long Dist[NUM_VERTEX];     //辅助数组,记录当前v到各点vi的最短距离int Path[NUM_VERTEX];           //保存最短路径bool Final[NUM_VERTEX];         //保存已经求得的最短路径的终点集合// srcVertex为源点编号void dijkstra(int srcVertex){    for (int i = 0; i < NUM_VERTEX; i++){        Dist[i] = g_graph[srcVertex][i];        Final[i] = false;        Path[i] = srcVertex;    }    Final[srcVertex] = true;        for (int i = 0; i < NUM_VERTEX; i++){        long long min = MAX;        int v = -1;        for (int j = 0; j < NUM_VERTEX; j++){            if (!Final[j] && Dist[j] < min){                min = Dist[j];                v = j;            }        }        if (v == -1)    break;        Final[v] = true;                for (int k = 0; k < NUM_VERTEX; k++){            if (!Final[k] && Dist[v] + g_graph[v][k] < Dist[k]){                Dist[k] = Dist[v] + g_graph[v][k];                Path[k] = v;            }        }    }}                // 测试                int main(){    int srcVertex = 0;    dijkstra(srcVertex);    for (int i = 0; i < NUM_VERTEX; i++){        if (Dist[i] < MAX){            cout << i << ": " << Dist[i] << "  ";            int k = i;            cout << "reverse path: " << i << " ";            while (k != srcVertex){                cout << Path[k] << " ";                k = Path[k];            }            cout << endl;        }        else{            cout << i << ": " << "No Path" << endl;        }    }    return 0;}


为什么只用一个Path数组就可以记录到所有终点的最短路径呢?因为这里Path[i]表示终点为vi的最短路径中vi的前驱节点。假设终点vi的前驱节点为vj,则到终点vi的路径一定是先到vj,然后通过弧(vj, vi)到vi。所以Path只需要记录每个节点的前驱节点即可。Path[i]需初始化为源点。