从某个源点到指定地点的最短路径(迪杰斯特拉算法的实现)

// algo7-6.cpp 实现算法7.15的程序。迪杰斯特拉算法的实现
#include"c1.h"
#define MAX_NAME 5 // 顶点字符串的最大长度+1
#define MAX_INFO 20 // 相关信息字符串的最大长度+1
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#include"c7-1.h" // 邻接矩阵存储结构
#include"bo7-1.cpp" // 邻接矩阵存储结构的基本操作
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 路径矩阵,二维数组
typedef int ShortPathTable[MAX_VERTEX_NUM]; // 最短距离表,一维数组
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix P,ShortPathTable D)
{ // 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度
	// D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。
	// final[v]为TRUE当且仅当v∈S,即已经求得从v0到v的最短路径算法7.15
	int v,w,i,j,min;
	Status final[MAX_VERTEX_NUM]; // 辅助矩阵,为真表示该顶点到v0的最短距离已求出,初值为假
	for(v=0;v<G.vexnum;++v)
	{
		final[v]=FALSE; // 设初值
		D[v]=G.arcs[v0][v].adj; // D[]存放v0到v的最短距离,初值为v0到v的直接距离
		for(w=0;w<G.vexnum;++w)
			P[v][w]=FALSE; // 设P[][]初值为FALSE,没有路径
		if(D[v]<INFINITY) // v0到v有直接路径
			P[v][v0]=P[v][v]=TRUE; // 一维数组p[v][]表示源点v0到v最短路径通过的顶点
	}
	D[v0]=0; // v0到v0距离为0
	final[v0]=TRUE; // v0顶点并入S集
	for(i=1;i<G.vexnum;++i) // 其余G.vexnum-1个顶点
	{ // 开始主循环,每次求得v0到某个顶点v的最短路径,并将v并入S集
		min=INFINITY; // 当前所知离v0顶点的最近距离,设初值为∞
		for(w=0;w<G.vexnum;++w) // 对所有顶点检查
			if(!final[w]&&D[w]<min) //在S集之外的顶点中找离v0最近的顶点,并将其赋给v,距离赋给min
			{
				v=w;
				min=D[w];
			}
			final[v]=TRUE; // 将v并入S集
			for(w=0;w<G.vexnum;++w) // 根据新并入的顶点,更新不在S集的顶点到v0的距离和路径数组
				if(!final[w]&&min<INFINITY&&G.arcs[v][w].adj<INFINITY&&(min+G.arcs[v][w].adj<D[w]))
				{ // w不属于S集且v0→v→w的距离<目前v0→w的距离
					D[w]=min+G.arcs[v][w].adj; // 更新D[w]
					for(j=0;j<G.vexnum;++j) // 修改P[w],v0到w经过的顶点包括v0到v经过的顶点再加上顶点w
						P[w][j]=P[v][j];
					P[w][w]=TRUE;
				}
	}
}
void main()
{
	int i,j;
	MGraph g;
	PathMatrix p; // 二维数组,路径矩阵
	ShortPathTable d; // 一维数组,最短距离表
	CreateDN(g); // 构造有向网g
	Display(g); // 输出有向网g
	ShortestPath_DIJ(g,0,p,d);//以g中位置为0的顶点为源点,球其到其余各顶点的最短距离。存于d中
	printf("最短路径数组p[i][j]如下:
");
	for(i=0;i<g.vexnum;++i)
	{
		for(j=0;j<g.vexnum;++j)
			printf("%2d",p[i][j]);
		printf("
");
	}
	printf("%s到各顶点的最短路径长度为
",g.vexs[0]);
	for(i=0;i<g.vexnum;++i)
		if(i!=0)
			printf("%s-%s:%d
",g.vexs[0],g.vexs[i],d[i]);
}

代码的运行结果:

请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): 6,8,0(见图768)
请输入6个顶点的值(<5个字符):
V0 V1 V2 V3 V4 V5
请输入8条弧的弧尾弧头权值(以空格作为间隔):
V0 V5 100
V0 V4 30
V0 V2 10
V1 V2 5
V2 V3 50
V3 V5 10
V4 V3 20
V4 V5 60
6个顶点8条边或弧的有向网。顶点依次是: V0 V1 V2 V3 V4 V5
G.arcs.adj:
32767 32767 10 32767 30 100
32767 32767 5 32767 32767 32767
32767 32767 32767 50 32767 32767
32767 32767 32767 32767 32767 10
32767 32767 32767 20 32767 60
32767 32767 32767 32767 32767 32767
G.arcs.info:
顶点1(弧尾) 顶点2(弧头) 该边或弧的信息:
最短路径数组p[i][j]如下:
0 0 0 0 0 0
0 0 0 0 0 0
1 0 1 0 0 0
1 0 0 1 1 0
1 0 0 0 1 0
1 0 0 1 1 1

V0到各顶点的最短路径长度为
V0-V1:32767
V0-V2:10
V0-V3:50
V0-V4:30
V0-V5:60

从某个源点到指定地点的最短路径(迪杰斯特拉算法的实现)

函数ShortestPath_DIJ()利用2 个辅助数组final[]和D[]求得给定点v0 到图G 中其余
各顶点的最短距离。D[]存放当前v0 到其余各顶点的最短距离,final[]的初值为FALSE。
final[]的值为TRUE,表示v0 到该顶点的最短距离已求出。图769 通过final[]和D[]的
变化演示了求解过程。

从某个源点到指定地点的最短路径(迪杰斯特拉算法的实现)

首先,final[]的初值中只有final[v0]为真,最短距离顶点集S 中只有顶点v0(源点,
此例中实参为V0)。D[]的初值是邻接矩阵中v0 行所对应的值。另令D[v0]=0(v0 到自己
的距离当然为0)。v0 到某顶点i 的最短距离可能是二者的直接距离G.arcs[v0][i].adj,也
可能是由v0 出发,经过其它顶点,最后到达顶点i 的距离。如图768 中V0 到V5 的最
短距离不是它们的直接距离100,而是由V0 经过V4、V3,最后到达V5 的距离60。
根据图769(a),在不属于S 集的顶点中,V0 到V2 的距离最短。可以断定,V0 到
V2 的距离10 是最短距离。V0 通过其它顶点绕道到达V2 的距离一定会比10 大,故将V2
并入S 集中(final[2]=TRUE)。并考察S 集外的顶点中,有没有哪个顶点i,使得V0 先到
V2(距离为10),再由V2 到达顶点i 比直接从V0 到达顶点i 的距离要小?也就是满足
10+G.arcs[2][i].adj<D[i]。如有,则改写D[i]。V0 本无直接到达V3 的路径,但有V0
→V2→V3 的路径,为10+G.arcs[2][3].adj=10+50=60,故改写D[3]=60,如图769(b)
所示。用这样的方法,依次将V4、V3 和 V5 并入S。详见图769(c)、(d)和(e)。
通过final[]和D[]可求得给定点v0 到图G 中其余各顶点的最短距离是多少。但却不
知道其间通过哪些顶点。矩阵P[][]有这些顶点的信息。以程序运行结果为例,1 维数组
p[2][]中的1 是V0 到V2 经过的顶点(只有V0 和V2 两个顶点);p[3][]中的1 是V0 到
V3 经过的顶点(V0、V3 和V4)。