您的位置:首页 > 其它

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

2013-10-24 22:11 225 查看
问题描述:给定带权有向图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]需初始化为源点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: