Skip to main content

Shortest Path Faster Algorithm (SPFA)

Algorithm​

SPFA is a improvement of the Bellman-Ford algorithm which takes advantage of the fact that not all attempts at relaxation will work. The main idea is to create a queue containing only the vertices that were relaxed but that still could further relax their neighbors. And whenever you can relax some neighbor, you should put him in the queue. This algorithm can also be used to detect negative cycles as the Bellman-Ford.

The worst case of this algorithm is equal to the O(nâ‹…m)\cal{O}(n \cdot m) of the Bellman-Ford, but in practice it works much faster and it works even in O(m)\cal{O}(m) on average. However be careful, because this algorithm is deterministic and it is easy to create counterexamples that make the algorithm run in O(nâ‹…m)\cal{O}(n \cdot m).

Implementation​

There are some care to be taken in the implementation, such as the fact that the algorithm continues forever if there is a negative cycle. To avoid this, it is possible to create a counter that stores how many times a vertex has been relaxed and stop the algorithm as soon as some vertex got relaxed for the -th time. Note, also there is no reason to put a vertex in the queue if it is already in.

const int INF = 1000000000;
vector<vector<pair<int, int>>> adj;

bool spfa(int s, vector<int>& d) {
int n = adj.size();
d.assign(n, INF);
vector<int> cnt(n, 0);
vector<bool> inqueue(n, false);
queue<int> q;

d[s] = 0;
q.push(s);
inqueue[s] = true;
while (!q.empty()) {
int v = q.front();
q.pop();
inqueue[v] = false;

for (auto edge : adj[v]) {
int to = edge.first;
int len = edge.second;

if (d[v] + len < d[to]) {
d[to] = d[v] + len;
if (!inqueue[to]) {
q.push(to);
inqueue[to] = true;
cnt[to]++;
if (cnt[to] > n)
return false; // negative cycle
}
}
}
}
return true;
}