单源最短路径问题,即在图中求出给定顶点到其它任一顶点的最短路径。在弄清楚如何求算单源最短路径问题之前,必须弄清楚最短路径的最优子结构性质。
一.最短路径的最优子结构性质
该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。
假设P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,则有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是从k到s的最短距离,那么必定存在另一条从k到s的最短路径P'(k,s),那么P'(i,j)=P(i,k)+P'(k,s)+P(s,j)
二.Dijkstra算法
由上述性质可知,如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点。那么(Vi...Vk)也必定是从i到k的最短路径。为了求出最短路径,Dijkstra就提出了以最短路径长度递增,逐次生成最短路径的算法。譬如对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+matrix[i][j]}。根据这种思路,
假设存在G=
1.从V-U中选择使dist[i]值最小的顶点i,将i加入到U中;
2.更新与i直接相邻顶点的dist值。(dist[j]=min{dist[j],dist[i]+matrix[i][j]})
3.知道U=V,停止。
代码实现:
=================Dijkstra.cpp==============================================
/*
*Dijkstra单元最短路径
*@author arhaiyun
*date:2013-09-29
*/
#include "stdafx.h"
#include
#include
#include "Graph.h"
using namespace std;
int main()
{
int i, n;
cout << "Please input vertex numbers:";
cin >> n;
adjmatrix g;
InitMatrix(g);
CreateMatrix(g);
cout << endl << "Adjacent matrix: " << endl;
PrintMatrix(g, n);
int *dist = new int [n];
EdgeNode ** path = new EdgeNode *[n];
cout << "Start point: ";
cin >> i;
Dijkstra(g, dist, path, i, n);
PrintPath(dist, path, i, n);
system("pause");
return 0;
}
=================Graph.h==============================================
#pragma once
#include
#define MaxVerNum 20
#define MaxValue 10000
typedef int adjmatrix[MaxVerNum][MaxVerNum]; //邻接矩阵的类型定义
typedef struct Node
{
int adjvex;
struct Node * next;
}EdgeNode; //指针数组path[]基类型定义
//初始化邻接矩阵表示的有向带权图
void InitMatrix(adjmatrix G)
{
for(int i = 0; i < MaxVerNum; i++)
{
for(int j = 0; j < MaxVerNum; j++)
{
G[i][j] = MaxValue;
}
}
}
//建立邻接矩阵表示的有权带向图(即通过输入图的每条边建立图的邻接矩阵)
void CreateMatrix(adjmatrix G)
{
int i, j, value;
cout<<"Input vertex ID and its value:"<> i >> j >> value;
while( i != -1)
{
G[i][j] = value;
in >> i >> j >> value;
}
}
//输出邻接矩阵表示的有向带权图(即输出图的每条边)
void PrintMatrix(adjmatrix G, int n)
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(G[i][j] == MaxValue)
{
cout << setiosflags(ios::left) << setw(5) << "Inf";
}
else
{
cout<< setiosflags(ios::left) << setw(5) << G[i][j];
}
}
cout << endl;
}
}
// 用到m路径path[m]更新到j路径path[js]
void PathUpdate(EdgeNode* path[], int vertex, int j)
{
EdgeNode* p;
p = path[j];
//delete path[j]中记录的路径
while(p != NULL)
{
path[j] = p->next;
delete p;
p = path[j];
}
//首先将到m的路径加入到path[j]
p = path[vertex];
EdgeNode *pCurrent, *pNode;
while(p != NULL)
{
pNode = new EdgeNode;
pNode->adjvex = p->adjvex;
if(path[j] == NULL)
{
path[j] = pNode;
}
else
pCurrent->next = pNode;
pCurrent = pNode;
p = p->next;
}
//在path[m]基础上添加m->j
pNode = new EdgeNode;
pNode->adjvex = j;
pNode->next = NULL;
pCurrent->next = pNode;
}
//求单源最短路径的Dijkstral算法
void Dijkstra(adjmatrix GA, int dist[], EdgeNode *path[], int i, int n)
{
bool *s = new bool[n];
for(int j = 0; j < n; j++)
{
if(j == i)
{
s[j] = true;
}
else
{
s[j] = false;
}
dist[j] = GA[i][j];
//路径初始化
if(dist[j] < MaxValue && j != i)
{
EdgeNode *pNode = new EdgeNode;
EdgeNode *pNext = new EdgeNode;
pNode->adjvex = i;
pNext->adjvex = j;
pNext->next = NULL;
pNode->next = pNext;
path[j] = pNode;
}
else
{
path[j] = NULL;
}
}
for(int k = 1; k < n -1; k++) //更新n-2次即可得到i到其它n-1个节点的最短路径
{
//选取新的最短路径节点进行距离的更新
int value = MaxValue;
int vertex = i;
for(int j = 0; j < n; j++)
{
if(s[j] == false && dist[j] < value)
{
value = dist[j];
vertex = j;
}
}
if( vertex != i)
{
s[vertex] = true; //节点值更新完毕,加入到最短节点的行列
}
else
{
break;
}
for(int j = 0; j < n; j++)
{
if(s[j] == false && GA[vertex][j] + dist[vertex] < dist[j])
{
//更新dist[j]的值
dist[j] = dist[vertex] + GA[vertex][j];
//更新到j的路径
PathUpdate(path, vertex, j);
}
}
}
delete []s;
}
//输出从源点到每个顶点的最短路径及长度的函数
void PrintPath(int dist[], EdgeNode *path[], int i, int n)
{
for(int j = 0; j < n; j++)
{
if(j != i)
{
cout << "[" << i << "," << j << "] min distance:"
<< dist[j] << ",route path:";
EdgeNode * pNode = path[j];
while(pNode != NULL && pNode->next != NULL)
{
cout<adjvex<<"->";
pNode = pNode->next;
}
if(pNode != NULL)
{
cout<adjvex;
}
}
cout<
输入:6
in.txt
0 1 10
0 2 12
1 3 16
1 4 25
2 0 4
2 1 3
2 3 12
2 5 8
3 4 7
5 3 2
5 4 10
-1 2 3
0