Relax All the Edges: Bellman-Ford
Get to know the Bellman-Ford algorithm and its applications in solving the shortest paths problem.
We'll cover the following...
Understanding the Bellman-Ford algorithm
The simplest implementation of Ford’s generic shortest-path algorithm was first sketched by Alfonso Shimbel in 1954, described in more detail by Edward Moore in 1957, and independently rediscovered by Max Woodbury and George Dantzig in 1957, by Richard Bellman in 1958, and by George Minty in 1958. (Neither Woodbury and Dantzig nor Minty published their algorithms.) In full compliance with Stigler’s Law, the algorithm is almost universally known as Bellman-Ford, because Bellman explicitly used Ford’s 1956 formulation of relaxing edges, although some authors refer to Bellman-Kalaba and a few early sources refer to Bellman-Shimbel.
The figure below shows a complete run of Dijkstra’s algorithm on a graph with negative edges. At each iteration, bold edges indicate predecessors; shaded vertices are in the priority queue; and the bold vertex is the next to be scanned.
The Shimbel / Moore / Woodbury-Dantzig / Bellman-Ford / Kalaba / Minty / Brosh algorithm can be summarized in one line:
- Relax all the tense edges, then recurse.
Algorithm
Implementation
import java.util.ArrayList;import java.util.Arrays;@SuppressWarnings("unchecked")public class BellmanFord {private static final int MAX_V = 1000;private static ArrayList<Edge>[] adj = new ArrayList[MAX_V];private static int[] dist = new int[MAX_V];private static boolean[] tense = new boolean[MAX_V];// Custom Pair classprivate static class Edge {int to;int weight;public Edge(int to, int weight) {this.to = to;this.weight = weight;}}private static void InitSSSP(int s) {Arrays.fill(dist, Integer.MAX_VALUE);dist[s] = 0;tense[s] = true;}private static boolean HasTenseEdge() {for (int u = 0; u < MAX_V; u++) {if (tense[u]) {return true;}}return false;}private static void Relax(int u, int v, int weight) {if (dist[u] != Integer.MAX_VALUE && dist[v] > dist[u] + weight) {dist[v] = dist[u] + weight;tense[v] = true;}}private static void BellmanFord(int s) {InitSSSP(s);while (HasTenseEdge()) {for (int u = 0; u < MAX_V; u++) {for (Edge edge : adj[u]) {int v = edge.to;int weight = edge.weight;if (tense[u] && tense[v]) {Relax(u, v, weight);}}tense[u] = false;}}}public static void main(String[] args) {for (int i = 0; i < MAX_V; i++) {adj[i] = new ArrayList<>();}adj[0].add(new Edge(1, 5));adj[1].add(new Edge(2, 2));adj[2].add(new Edge(3, 3));adj[3].add(new Edge(4, -4));adj[4].add(new Edge(1, 1));BellmanFord(0);for (int i = 0; i < MAX_V; i++) {System.out.println("Shortest distance from vertex 0 to " + i + " is " + dist[i]);}}}
Explanation
- Lines 20–24: This function initializes the single-source shortest path algorithm by setting all distances to the maximum value except for the source vertex which is set to zero, and marking it as tense.
- Lines 42–56: This is the implementation of the Bellman-Ford algorithm explained above.
- Lines 62–67: These lines of code add edges in the example graph.
The following lemma is the key to proving both the correctness and efficiency of Bellman-Ford. For every vertex and non-negative integer , let denote the length of the shortest walk in from to consisting of at most edges. In particular, and for all .
Lemma: For every vertex and non-negative integer , after iterations of the main loop of Bellman-Ford, we have .
Proof: The proof proceeds by induction on . The base case is trivial, so assume . Fix a vertex , and let be the shortest walk from to consisting of at most edges (breaking ties arbitrarily). By definition, has length . There are two cases to consider:
- Suppose has no edges. Then W must be the trivial walk from to , so and . We set in , and can never increase, so we always have