Bellman-Ford Algorithm (C++)
Table of contents
Things to Remember
- We have a naive version and a dynamic programming version.
- Can handle negative edge weights.
- Detects negative cycles.
- We need to build an adjacency list to represent the graph.
- We do not use a priority queue.
Adjacency List
The adjacency list adj
needs to be built with given inputs:
using Dist = int;
using Vertex = int;
using EdgeTo = pair<Dist, Vertex>; // Do not confuse this with the PqElem later
vector<vector<EdgeTo>> adj(n + 1); // If vertices are 1-indexed
// Build the adjacency list with loop
adj[u].push_back({w, v}); // Edge from u to v with weight w
Initialization
Distance and Predecessor Vectors
We will keep track of the current shortest distance and current predecessor of each vertex.
vector<AccDist> cur_dist(n + 1, INT_MAX);
vector<Vertex> pred(n + 1, -1);
Source Initialization
Let’s say we are starting from vertex s
.
First, we know the shortest distance to s
from s
is 0
.
cur_dist[s] = 0;
Obviously, predecessor of the source vertex remains -1
.
The Loop (Naive Version)
for (int round = 1; round < n; ++round) {
for (int u = 1; u <= n; ++u) {
for (const EdgeTo& e : adj[u]) {
int w = e.first;
int v = e.second;
if (cur_dist[u] != INT_MAX && cur_dist[v] > cur_dist[u] + w) {
cur_dist[v] = cur_dist[u] + w;
pred[v] = u;
}
}
}
}
Detecting Negative Cycles
To detect negative cycles, we need to run the loop one more time.
If we can relax any edge, then there is a negative cycle.
for (int u = 1; u <= n; ++u) {
for (const EdgeTo& e : adj[u]) {
int w = e.first;
int v = e.second;
if (cur_dist[u] != INT_MAX && cur_dist[v] > cur_dist[u] + w) {
cout << "Negative cycle detected!" << endl;
return;
}
}
}
Adjacency List in DP Version
In the bottom-up DP version, we need to build the adjacency list so that each index corresponds to a vector of incoming edges.
vector<vector<EdgeFrom>> adj(n + 1);
...
adj[v].push_back({w, u}); // For each edge (u, v) in the input
Initialization in DP Version
We need a memoization table W
to store the shortest distances. The rows correspond to the the maximum number of edges a path can have, and the columns correspond to the destination vertex.
vector<vector<int>> W(n);
for (int m = 0; m < n; ++m) {
W[m] = vector<int>(n + 1, INT_MAX);
for (int i = 1; i <= n; ++i) {
if (i == k) W[m][i] = 0;
}
}
All the entries are initialized to INT_MAX
except for the source vertex column, which can be reached in 0
distance.