The Bellman-Ford Algorithm is an algorithm that computes the length of the shortest path from a vertex to every vertex in a directed graph with edge weights and no negative cycles in time and space.
Tip
This problem can also be solved by the Floyd-Warshall Algorithm in time and space.
Tip
This problem can also be solved by Johnson’s Algorithm in
time and space, or
time and space.
Algorithm 0
Lemma
Let denote the length of the shortest path from to passing through at most edges, denote the set of edges directed toward . Then
Lemma
Let denote the length of the shortest path from to , then
Proof
Let , where and , be a shortest path from to passing through the least number of edges.
If , applying the Pigeonhole Principle yields
Therefore, is a shortest path passing through fewer edges.
By contradiction, it follows that .
Applying the lemmas to find and yields an algorithm that solves the problem in time and space.
std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
std::vector dist(n, std::vector(n, inf));
dist[0][s] = 0;
for (int i = 1; i < n; i++) {
dist[i] = dist[i - 1];
for (int j = 0; j < m; j++) {
dist[i][v[j]] = std::min(dist[i][v[j]], dist[i - 1][u[j]] + w[j]);
}
}
return dist[n - 1];
}Algorithm 1
Based on Algorithm 0, ignoring the first dimension yields an algorithm that solves the problem in time and space.
std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
std::vector dist(n, inf);
dist[s] = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
dist[v[i]] = std::min(dist[v[i]], dist[u[i]] + w[i]);
}
}
return dist;
}Proof
It is easy to prove that each value in the
distin Algorithm 1 is always less than or equal to the corresponding value in thedistin Algorithm 0.
Algorithm 2
Based on Algorithm 1, maintaining a queue to skip unchanged values that cannot be used to update other values yields an algorithm that solves the problem in and space.
std::vector<int> bellman_ford(int n, int m, const std::vector<int> &u, const std::vector<int> &v, const std::vector<int> &w, int s) {
std::vector<std::vector<std::pair<int, int>>> adj(n);
for (int i = 0; i < m; i++) {
adj[u[i]].emplace_back(v[i], w[i]);
}
std::vector dist(n, inf);
dist[s] = 0;
std::queue<int> q;
q.push(s);
std::vector vis(n, false);
vis[s] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for (auto [v, w] : adj[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
if (!vis[v]) {
q.push(v);
vis[v] = true;
}
}
}
}
return dist;
}