所谓单源最短路径,是指从一个顶点(源点)出发到其他各顶点的最短路径,即给定有向网G和源点Vk,求从Vk到G中其他各顶点Vj(j=1,2,····,n,j!=k)的最短路径。
迪杰斯特拉提出了一种按路径长度递增的次序产生最短路径的算法。其基本思想是,把网中所有顶点分成两组,第一组是已确定最短路径的顶点集合S,第二组是尚未确定最短路径的顶点集合V;把V中的顶点按最短路径长度递增的顺序逐个添加到S中,添加过程中始终保持从Vk到S中每个顶点的最短路径长度都不大于从Vk到V中任何顶点的最短路径长度,直到从Vk出发可以到达的顶点都在S中为止。
一开始,S中只有顶点Vk,其余顶点在V中。引入一维数组dist,用dist[i]表示当前时刻所找的从源点到每个中点Vi的最短路径长度;其初始值为dis[k]=0;若存在弧(vk,vi),则dist[i]为其弧上的权值,否则从Vk到Vi无弧时dist[i]=max。然后每次从V中的顶点选取一个dist值最小的顶点Vj(dist[j]=min{dist[i]|Vi属于V})加入到S中,并对V中顶点的dist值进行相应的修改,即若以加入S中的顶点Vj作为中间顶点使得V中某顶点的dist值更小时要相应地修改该顶点的dist值。这样从V中选一个顶点加入到S中,对V中的顶点的dist值修改一遍,只需做n-1次就可求得Vk到其余各顶点的最短路径。
在求最短路径的过程中,最短路径长度已记在dist数组中,同时需要把路径也记下来。为此设一个一维数组pre,pre[i]存放从Vk到Vi的路径上Vi前一个顶点的序号;若Vk到Vi无路径可达,则vi的前一个顶点序号用0表示(即pre[i]=0)。在算法结束时,沿着顶点Vi对应的pre[i]向前追溯就能确定从Vk到Vi的最短路径,其最短路径长度为dist[i].
设有向网用邻接矩阵a表示,a[i,j]表示弧(Vi,Vj)上的权值,无弧(Vi,Vj)时a[i,j]为max;a[i,j]=0,当Vi进入S中时,用a[i,j]=1来标识。求有向图中从顶点Vk出发到其他各顶点的最短路径的Dijkstra算法如下:
void dijkstra(int a[][],int k,int pre[],int dist[],int n)//求用邻接矩阵a表示的有向网中从Vk到其他各顶点最短路径
{
int i,j,p,min;//定义局部变量
for(i=1;i<=n;i++)//数组dist,pre初始化
{
dist[i]=a[k][i];
if(dist[i]<max)
pre[i]=k;
else
pre[i]=0;
}
pre[k]=0;
dist[k]=0;
a[k][k]=1;//Vk加入S中控制n-1次按长度递增产生最短路径
for(p=1;p<=n-1;p++)
{
min=max;//预置最短路径长度为max
j=-1;//设结束标志
for(i=1;i<=n;i++)
if(a[i][i]==0&&dist[i]<min)
{
j=i;
min=dist[i];//在V中选dist最小的点
}
if(j==-1) break;//已无顶点可加入S,退出
else
{
a[j][j]=1;//把选出的顶点Vj加入S中
for(i=1;i<=n;i++)//更新V中顶点的dist和pre值
if(a[i][i]==0&&(min+a[j][i]<dist[i]))
{
dist[i]=min+a[j][i];
pre[i]=j;
}
}
}
}//dijkstra