本篇博客将考察各种最短路径问题。
无权最短路径
Dijkstra 算法
具有负边值的图
无圈图
所有顶点对间的最短路径
最短路径的例子–词梯游戏
输入是一个赋权图:与每条边 (vi, vj) 相联系的是穿越该边的开销(或称为值)ci,j 。一条路径v1v2……vN的值是 
这叫作赋权路径长(weighted path length)。而无权路径长只是路径上的边数,即 N-1。
单源最短路径问题(Single-Source Shortest-Path Problem):
给定一个赋权图 G=(V, E) 和一个特定顶点 s 作为输入,找出从 s 到 G 中每一个其他顶点的最短赋权路径。
例如,在图1 中,从 v1 到 v6 的最短赋权路径的值为6,路径为 v1 -> v4 -> v7 -> v6 ;在这两个顶点间的最短无权路径长为2。

前面例子中没有负值边,图2 中的图就指出了负边可能产生的问题。从 v5 到 v4 的路径值为1,但通过循环 v5, v4, v2, v5, v4 存在一条更短的路径,它的值为-5,这个最短路径仍然可以通过循环达到任意小。这个循环叫作负值圈(negative-const cycle)。在没有负值圈时,从 s 到 s 的最短路径为0。

我们可能使用图建立航线或其他大规模运输线路的模型,并利用最短路径算法计算两点间的最佳路线。在这样的以及许多实际应用中,我们可能想要找出从一个顶点 s 到另一个顶点 t 的最短路径。 当前,还不存在找出从 s 到一个顶点的路径比找出从 s 到所有顶点路径更快得算法。
我们将考虑求解该问题 4种形态的算法。首先,要考虑无权最短路径问题,并指出如何以 O(|E|+|V|) 时间求解它。其次,如果假设没有负边,那么如何求解赋权最短路径问题,这个算法在使用一些合理的数据结构实现时的运行时间为 O(|E| log|V|)。如果图有负边,则提供一个简单解法,时间界为 O(|E|·|V|)。最后,将以线性时间解决无圈图这种特殊情形的赋值问题。
无权最短路径
图3 表示一个无权图G,使用某个顶点 s 作为输入参数,我们想要找出从 s 到所有其他顶点的最短路径。显然,这是赋权最短路径问题的特殊情形,因为可以为所有的边都赋以权1。

设我们选择 s 为 v3,此时可立即得到 s 到 v3 的最短路径长为0,将其标记,如图4 所示。
然后开始寻找所有从 s 出发距离为1 的顶点,这可以通过考查邻接到 s 的那些顶点找到,即 v1 和 v6 ,将它表示在图5 中;然后找出从 s 出发最短路径恰为2 的顶点,找出所有邻接到 v1 和 v6 的顶点,这次搜索告诉我们,到 v2 和 v4 的最短路径长为2。

最后,通过考查那些邻接到刚被赋值的 v2 和 v4 的顶点可以发现, v5 和 v7 各有一条三边的最短路径,现在所有的顶点都已经被计算,如图7 所示。

这种搜索图的方法就是广度优先搜索(breadth-first search)。该方法按层处理顶点:距开始点最近的那些顶点首先被求值,而最远的那些顶点最后被求值,这很像树的层序遍历(level-order traversal)。
图8 显示出该算法要用到的表的初始配置,记录了该算法的进行过程。对于每个顶点,我们跟踪3 条信息。首先,把从 s 开始到顶点的距离放到 dv 栏中,开始时除 s 外所有的顶点都不可达。pv 栏中的项为簿记变量,它将使我们显示出实际的路径。known 栏中的项在顶点被处理后置为 true。当一个顶点被标记为 known 时,我们就有了不会再找到更便宜的路径的保证,因此对该顶点的处理实质上已经完成。
无权最短路径算法的伪代码
void Graph::unweighted(Vertex s)
{
for each Vertex v
{
v.dist = INFINITY;
v.known = false;
}
s.dist = 0;
for(int currDist=0;currDist<NUM_VERTICES;currDist++)
for each Vertex v
if (!v.known && v.dist == currDist)
{
v.known = true;
for each Vertex w adjacent to v
if (w.dist == INFINITY)
{
w.dist = currDist + 1;
w.path = v;
}
}
}
由于双层嵌套的 for 循环,因此该算法的运行时间为 O(|V|2)。一个明显的低效之处在于,尽管所有的顶点早已成为 known 了,但外层循环还是要继续,直到 NUM_VERTICES -1 为

本文深入探讨了图论中的最短路径问题,包括无权最短路径、Dijkstra算法、负权边处理、无圈图以及所有顶点对间的最短路径。介绍了Dijkstra算法在无负权图中的应用,以及在存在负权边时可能出现的问题。通过实例展示了词梯游戏中的最短路径计算,阐述了如何使用C++实现这一过程。

2227

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



