最小加权路径:加权有向图两顶点之间权值之和最小的路径(以下称为最短路径)。
注意到一个事实:如果已知从顶点A到B的最短路径,而这条路径经过顶点C,则从A到C的最短路径一定在这条最短路径上(反证可知)。进一步,如果C是从A到B最短路径上经过的倒数第二个顶点,即经过C的下一个顶点是B,那么AB最短路径=AC最短路径+CB。
基于以上事实,如果从源顶点A到目标顶点B1、B2、B3……Bn的最短路径都已知,现在加入一个新目标顶点B(n+1),那么从A到B(n+1)的最短路径是[AB1最短路径+B1B(n+1)]、[AB2最短路径+B2B(n+1)]……[ABn最短路径+BnB(n+1)]以及AB(n+1)中最小的一个。
算法实现
基本定义:
该加权有向图有n个顶点,编号为1~n。(以下数组中下标为0的位置均无实际意义)
有向边使用邻接数组a[n+1][n+1]存储,其所存数值大小代表有向边的权重(有向边的权重均为正数),当边不存在时,数组中对应位置存储的数值是noEdge。
源顶点:sourceVertex。
目的顶点:targetVertex。
数组distanceFromSource[n+1]用于记录源顶点到所有顶点的最短路径长度。初始化时暂时存放源顶点到其他所有顶点的有向边距离,有向边不存在时存放noEdge。
数组predecessor[n+1]用于记录最短路径上到达各个顶点之前的顶点。通过这个数组,可以从目的顶点回溯到源顶点,从而确定最短路径上经过的所有顶点。初始化时源顶点的所有邻接顶点存放源顶点,源顶点存放0,其他顶点存放-1。
链表newReachableVertices用于临时存放最短路径刚刚发生了变化的顶点,因为这些顶点的最短路径发生了变化,所以他们所有的邻接顶点都要重新确定最短路径。初始化时将源顶点的所有邻接顶点存入其中。
开始循环,直到链表newReachableVertices为空:
1.先找出链表newReachableVertices中目前distanceFromSource最小的顶点,记为minDistanceVertex,并从链表中删除该顶点。(因为newReachableVertices中的其他任何顶点都不可能影响到这个顶点)
2.然后遍历该顶点的所有邻接顶点,判断它们的distanceFromSource是否要发生修改,即是否要替换成源顶点到minDistanceVertex最短路径加上minDistanceVertex到其邻接顶点的距离。如果发生替换,则将该邻接顶点的predecessor修改成minDistanceVertex(因为此时从源顶点到该顶点的最短路径经过了minDistanceVertex),并且若该邻接顶点不在链表newReachableVertices中,则将其加入链表中(因为该顶点的最短路径已经发生了变化)。
循环结束之后distanceFromSource中的数据就是从源顶点到各个顶点的最小路径长度,若distanceFromSource[targetVertex]仍为noEdge,说明源顶点到目的顶点并不连通。而从predecessor中,可以从目的顶点找回到源顶点,从而确定这条最短路径上所经过的所有顶点。
代码
这个函数属于加权有向图类adjacencyWDigraph,此处不做详细说明。
关于类adjacencyWDigraph的完整设计,请见有向图(邻接数组描述)
void Dijkstra(int sourceVertex, int targetVertex)//Dijkstra算法计算两顶点之间最小加权路径
{
//以下为初始化,可简化
T* distanceFromSource = new T[n + 1];//用于记录每一个顶点与源顶点的加权最小总距离
for (int i = 0; i <= n; i++)//初始化,暂定源顶点到每个顶点有向边的加权距离(若源顶点与某定点不存在有向边,则这段距离是noEdge)
distanceFromSource[i] = a[sourceVertex][i];

介绍Dijkstra算法原理及实现,用于寻找加权有向图中最短路径。通过不断更新顶点距离并选择当前距离最小的顶点进行扩展,最终得到源点到各顶点的最短路径。
最低0.47元/天 解锁文章
1606

被折叠的 条评论
为什么被折叠?



