Dijkstra算法的具体实现方法为:
a) S中存放已找到最短路径的顶点,初始时,集合S中只有一个顶点,即源点v0;
b) T中存放当前还未找到最短路径的顶点;
2.在T集合中选取当前长度最短的一条最短路径(v0,…,vk),从而将vk加入到顶点集合S中,并修改源点v0到T中各顶点的最短路径长度;重复这一步骤,直到所有的顶点都加入到集合S中,算法就结束了。
算法实现:
在Dijkstra算法里,为了求源点v0到其他各顶点vi的最短路径及其长度,需要设置3个数组:
a) dist[n]:dist[i]表示当前找到的从源点v0到终点vi的最短路径的长度,初始时,dist[i]为Edge[v0][i],即邻接矩阵的第v0行。
b) S[n]:S[i]为0表示顶点vi还未加入到集合S中,S[i]为1表示vi已经加入到集合S中。初始时,S[v0]为1,其余为0,表示最初集合S中只有顶点v0。
c) path[n]:path[i]表示v0到vi的最短路径上顶点vi的前一个顶点序号。采用“倒向追踪”的方法,可以确定v0到顶点vi的最短路径上的每个顶点。
在Dijkstra算法里,重复做以下3步工作:
1) 在数组dist[n]里查找S[i] != 1,并且dist[i]最小的顶点u;
2) 将S[u]改为1,表示顶点u已经加入进来了;
3) 修改T集合中每个顶点vk的dist及path数组元素值:当S[k] != 1,且顶点u到顶点vk有边(Edge[u][k]<MAX),且dist[u] + Edge[u][k] < dist[k],则修改dist[k]为dist[u] + Edge[u][k],修改path[k]为u。
因此Dijkstra算法的递推公式(求源点v0到各顶点的最短路径)为:
eg:
利用Dijkstra算法求下图中顶点0到其他各顶点的最短路径长度,并输出对应的最短路径。
假设数据输入时采用如下的格式进行输入:首先输入顶点个数n,然后输入每条边的数据。每条边的数据格式为:u v w,分别表示这条边的起点、终点和边上的权值。顶点序号从0开始计起。最后一行为-1 -1 -1,表示输入数据的结束。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 20;
const int INF = 1000010;
int dist[MAXN];
int path[MAXN];
int S[MAXN];
int Edge[MAXN][MAXN];
int n;
void Dijkstra(int v0)
{
int i, j;
memset(dist, 0, sizeof(dist));
for (i = 0; i < n; ++i)
{
dist[i] = Edge[v0][i];//初始时dist中存放v0所在的行
S[i] = 0;
if (i != v0 && dist[i] < INF)
path[i] = v0;
else
path[i] = -1;
}
S[v0] = 1, dist[v0] = 0;//只有v0 在S中
for (i = 0; i < n-1; ++i)
{
int MIN = INF, v = v0;
for (j = 0; j < n; ++j)
{
if ( !S[j] && MIN > dist[j] )//在T中找具有最短路径的定点v
{
MIN = dist[j];
v = j;
}
}
S[v] = 1;//表示v已经加入进来
for (j = 0; j < n; ++j)//由于v的加入,可能会导致v0到T中顶点dist[]值“缩短”,如果dist的值修改自然也要修改path
{
if (!S[j] && Edge[v][j] < INF && (dist[v] + Edge[v][j] < dist[j]))
{
dist[j] = dist[v] + Edge[v][j];
path[j] = v;
}
}
}
}
int main()
{
int i, j;
int u, v, w;
cin>>n;
while (1)
{
cin>>u>>v>>w;
if(u == -1 && v == -1 && w == -1)
break;
Edge[u][v] = w;
}
for (i = 0; i < n; ++i)
{
for (j = 0; j < n; ++j)
{
if(i == j)
Edge[i][j] = 0;
else if(Edge[i][j] == 0)
Edge[i][j] = INF;
}
}
Dijkstra( 0 );
int shortest[MAXN];
for (i = 1; i < n; ++i)
{
cout<<dist[i]<<"\t";
memset(shortest, 0, sizeof(shortest));//找到从v0到i的最短路径上的点
int k = 0;
shortest[k] = i;
while (path[ shortest[k] ] != 0)
{
k++;
shortest[k] = path[ shortest[k-1] ];
}
k++;
shortest[k] = 0;
for(j = k; j > 0; --j)
cout<<shortest[j]<<" -> ";
cout<<shortest[0]<<endl;
}
return 0;
}
dijkstra与Prim算法有很大的相似性,Prim中lowcost存放的是T中各个顶点到S中各个顶点的权值最小值,而修改的时候,lowcost[k] = min{lowcost[k], Edge[v][k]}