xxx 图论中的最短路径快速算法(SPFA)
题目描述
最短路径快速算法(Shortest Path Faster Algorithm, SPFA)是一种用于求解带权有向图(或无向图)中单源最短路径的算法。它是 Bellman-Ford 算法的一种优化版本,通过动态更新候选节点来减少不必要的松弛操作。SPFA 适用于含有负权边的图,并能检测负权环。其平均时间复杂度为 O(kE),其中 k 为常数,但在最坏情况下(如存在负权环或特定结构的图)会退化为 O(VE)。
解题过程
-
算法核心思想
SPFA 维护一个队列(或栈)来存储待处理的节点。初始时,将源节点加入队列,并标记其距离为 0。然后不断从队列中取出节点,对其所有邻接边执行松弛操作(即尝试通过当前节点缩短邻接节点的距离)。若邻接节点的距离被更新,且该节点不在队列中,则将其加入队列。重复此过程直到队列为空。若某个节点被松弛次数超过 V 次(V 为节点数),则说明图中存在负权环。 -
详细步骤
-
初始化:
设置一个距离数组dist[],初始时dist[源节点] = 0,其余节点为无穷大(∞)。
创建一个队列queue,将源节点入队,并记录每个节点是否在队列中的标记数组inQueue[](初始时仅源节点标记为真)。
可选:记录每个节点被松弛次数的数组count[](用于检测负权环)。 -
主循环:
当队列非空时,取出队首节点u,并将其inQueue[u]标记为假。
遍历u的所有邻接边(u, v, w)(w 为边权值):
若dist[v] > dist[u] + w,则更新dist[v] = dist[u] + w。
若v不在队列中,则将v入队,并标记inQueue[v] = true,同时增加count[v]++。
若count[v] > V,则算法终止并报告“存在负权环”。 -
终止条件:
队列为空时,dist[]数组即为源点到各点的最短距离。
若检测到count[v] > V,则说明存在从源点可达的负权环。
-
-
举例说明
考虑一个包含 4 个节点的有向图,边权如下:- 边 (0→1): 权值 4
- 边 (0→2): 权值 5
- 边 (1→3): 权值 -2
- 边 (2→3): 权值 3
- 边 (3→1): 权值 1(可能形成环)
以节点 0 为源点:
- 初始:
dist[0]=0,其他为 ∞,队列[0]。 - 处理节点 0:更新节点 1(dist[1]=4)、节点 2(dist[2]=5),队列变为
[1, 2]。 - 处理节点 1:更新节点 3(dist[3]=4 + (-2)=2),队列变为
[2, 3]。 - 处理节点 2:尝试更新节点 3(2+3=5 > 当前 dist[3]=2,无需更新),队列剩
[3]。 - 处理节点 3:更新节点 1(dist[1]=2+1=3 < 原值 4),重新将节点 1 入队,队列为
[1]。 - 处理节点 1:再次更新节点 3(dist[3]=3 + (-2)=1),队列变为
[3]。 - 后续操作会继续更新节点 1 和 3,但若图中无负权环,最终队列会为空。若存在负权环(如边权为负的环),则
count[]会超限。
-
关键优化与注意事项
- SPFA 的效率依赖于图的结构,稀疏图中表现接近 Dijkstra 算法,但稠密图或含负权环时可能较慢。
- 使用队列时,SPFA 类似 BFS;使用栈可能更快收敛于某些图,但稳定性较差。
- 负权环检测需严格通过节点入队次数判断,避免无限循环。
通过以上步骤,SPFA 能高效处理含负权边的最短路径问题,同时兼顾负权环检测功能。