图论中的最短路径快速算法(SPFA)
字数 1531 2025-11-01 15:29:06
图论中的最短路径快速算法(SPFA)
题目描述
最短路径快速算法(Shortest Path Faster Algorithm,SPFA)是解决带权有向图(或无向图)中单源最短路径问题的一种算法。它是Bellman-Ford算法的一种优化版本,通过使用队列来避免不必要的松弛操作,从而在许多情况下(尤其是稀疏图)获得更好的平均时间复杂度。该算法能够处理带有负权边的图,但如果图中存在从源点可达的负权环,算法会检测到这一情况并报告问题。
核心概念
- 单源最短路径:从一个指定的源点出发,计算到图中所有其他顶点的最短路径距离。
- 松弛操作:对于图中的一条边(u, v),权重为w,如果发现通过顶点u可以使得到达v的当前距离估计值变小,则更新该估计值。即如果
dist[v] > dist[u] + w(u, v),则设置dist[v] = dist[u] + w(u, v)。 - 负权环:一个总权重为负的环。如果存在从源点可达的负权环,则最短路径问题无解,因为可以无限次绕行该环使得路径总权任意小。
解题步骤
SPFA算法可以看作是BFS的改进,它使用一个队列来管理哪些顶点可能需要被松弛。
-
初始化
- 创建一个距离数组
dist[],大小为顶点数。将源点s的dist[s]初始化为0,其他所有顶点的dist[]初始化为一个很大的数(如无穷大)。 - 创建一个队列
Q,初始时只包含源点s。 - (可选)创建一个数组
inQueue[]来标记顶点当前是否在队列中,避免重复入队。初始时,只有inQueue[s]为真。 - (用于检测负环)创建一个数组
count[]来记录每个顶点入队的次数。初始化为0。当某个顶点的入队次数超过顶点总数时,说明存在负权环。
- 创建一个距离数组
-
主循环
只要队列Q不为空,就执行以下步骤:
a. 出队:从队列Q中取出队首顶点u,并将其inQueue[u]标记为假。
b. 松弛邻接边:遍历顶点u的所有出边(即邻接顶点v)。对于每条边(u, v),其权重为w,尝试进行松弛操作:- 检查是否满足
dist[v] > dist[u] + w。 - 如果满足,则更新
dist[v] = dist[u] + w。
c. 判断入队:如果v的距离被更新了,并且v当前不在队列中(即inQueue[v]为假),则将v加入队列Q的末尾,并将inQueue[v]标记为真。同时,增加v的入队次数count[v] += 1。
d. 检测负环:如果count[v]超过了图中顶点的总数目V,则算法终止,并报告图中存在从源点可达的负权环。
- 检查是否满足
-
终止与输出
- 当队列为空时,算法正常结束。此时
dist[]数组中存储的就是从源点s到各顶点的最短路径距离(如果某个顶点的距离仍为初始的无穷大,则表示从s无法到达该顶点)。 - 如果在过程中因检测到负环而提前终止,则输出存在负权环的错误信息。
- 当队列为空时,算法正常结束。此时
算法特点与复杂度
- 优点:在随机图或稀疏图上,平均时间复杂度往往优于Bellman-Ford算法的O(VE),接近O(kE),其中k是一个较小的常数。能处理负权边。
- 缺点:最坏情况下的时间复杂度仍为O(VE),与Bellman-Ford相同。存在被特殊构造的数据使其性能退化的风险。
- 与Bellman-Ford的区别:Bellman-Ford算法会对所有边进行V-1轮松弛,而SPFA只对“可能更新其他顶点距离”的顶点(即其距离刚刚被更新的顶点)的邻接边进行松弛,减少了大量不必要的操作。