SPFA算法是一种求解单源最短路径问题的算法,它是Bellman-Ford算法的队列优化¹²³。它适用于含有负权边的图,但不能处理负权环¹⁴。它的原理是对图进行V-1次松弛操作,得到所有可能的最短路径³。
形象化地说,SPFA算法就像一个人在一个城市里找到从起点到终点的最短路线。他先把起点放入一个队列中,然后每次从队列中取出一个点,看看这个点能否通过一条边到达另一个点,并且使得到达那个点的距离更短。如果可以,就更新那个点的距离,并把它放入队列中(如果它已经在队列中就不用重复放入)。这样不断重复,直到队列为空或者达到V-1次松弛操作为止。
用C++演示一个例子:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int INF = 1e9; //定义无穷大
const int MAXN = 100; //定义最大节点数
int n, m; //节点数和边数
int dist[MAXN]; //存储起点到每个节点的最短距离
bool inq[MAXN]; //标记每个节点是否在队列中
vector<pair<int, int>> adj[MAXN]; //邻接表存储图,每个pair表示一条边(终点,权值)
void spfa(int s) { //s为起点
fill(dist, dist + n, INF); //初始化所有距离为无穷大
fill(inq, inq + n, false); //初始化所有节点不在队列中
queue<int> q; //创建一个空队列
q.push(s); //把起点放入队列
dist[s] = 0; //更新起点距离为0
inq[s] = true; //标记起点在队列中
while (!q.empty()) { //当队列不为空时循环
int u = q.front(); //取出队首元素
q.pop(); //弹出队首元素
inq[u] = false; //标记该元素不在队列中
for (auto p : adj[u]) { //遍历该元素相邻的所有边
int v = p.first; //获取终点
int w = p.second; //获取权值
if (dist[u] + w < dist[v]) { //如果可以松弛该边
dist[v] = dist[u] + w; //更新终点距离
if (!inq[v]) { //如果终点不在队列中
q.push(v); //把终点放入队列
inq[v] = true; //标记终点在队列中
}
}
}
}
}
Source: (1) SPFA算法_百度百科. https://baike.baidu.com/item/SPFA算法/8297411
(2) SPFA算法 - SHHHS - 博客园. https://www.cnblogs.com/shadowland/p/5870640.html
(3) 最短路径问题—SPFA算法详解_用spfa解决最短路径问题_Ouyang_Lianjun的博客-CSDN博客. https://blog.csdn.net/qq_35644234/article/details/61614581
(4) Shortest path faster algorithm - Wikipedia. https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm