Topics › Graphs › Shortest Path Algorithms and Problems
Bellman Ford Algorithm
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a directed weighted graph with V vertices numbered 0 to V - 1, as a list of edges [u, v, w]. Weights may be negative. Given a source src, return an array where entry i is the shortest distance from src to i, using 10^8 for vertices that cannot be reached. If the graph contains a negative-weight cycle reachable from src, shortest distances are not defined (you could loop forever and keep lowering the cost), so return [-1] instead.
Constraints (GeeksforGeeks “Distance from the Source”): 1 ≤ V ≤ 500, 1 ≤ E ≤ V(V-1), -1000 ≤ w ≤ 1000.
Example 1
V = 3, edges = [[0,1,5], [1,0,3], [1,2,-1], [2,0,1]], src = 2
answer = [1, 6, 0] // 2 -> 0 costs 1, then 0 -> 1 costs 5 more
Example 2
V = 3, edges = [[0,1,1], [1,2,-1], [2,0,-1]], src = 0
answer = [-1] // 0 -> 1 -> 2 -> 0 has total weight -1, a negative cycle
Dijkstra cannot be used here. It finalises a vertex the moment it leaves the heap, assuming no later path can be shorter. A negative edge discovered later can break that assumption. Bellman-Ford makes no such assumption: it keeps improving distances until they cannot improve any further.
The idea behind Bellman-Ford
Relaxation. For an edge u → v with weight w, if dist[u] + w < dist[v], the path “best route to u, then this edge” beats the best known route to v, so we set dist[v] = dist[u] + w. Every shortest-path algorithm is a strategy for choosing which edges to relax and when. Bellman-Ford’s strategy is the bluntest one: relax every edge, and repeat.
Why V - 1 rounds are enough. If there is no negative cycle, some shortest path to each vertex is simple, so it has at most V - 1 edges: src = x0 → x1 → … → xm with m ≤ V - 1. Claim: after round r, dist[x_r] is correct. Round 0 holds because dist[src] = 0. If dist[x_(r-1)] is correct after round r - 1, then during round r the edge x_(r-1) → x_r gets relaxed and sets dist[x_r] to its true value. Relaxations never push a value below the true distance, because every value written is the length of an actual path. So after V - 1 rounds every distance is final, whatever order the edges are listed in.
Why round V detects a negative cycle. If all distances are final after V - 1 rounds, then one more round changes nothing. Conversely, suppose a negative cycle c0 → c1 → … → c0 is reachable and no edge on it can be relaxed: dist[c_(i+1)] ≤ dist[c_i] + w_i for every edge of the cycle. Adding these inequalities around the cycle, the dist terms cancel and we get 0 ≤ total cycle weight, contradicting that the cycle is negative. So some edge on it can always be relaxed, and round V will find it.
Approach 1: Classic Bellman-Ford
Intuition. Run the proof literally: V - 1 full rounds of relaxing every edge, then one extra round that only checks whether anything could still improve. Only relax from vertices that have been reached (dist[u] != INF). Otherwise INF + w with a negative w could look like a real distance, and a cycle that src cannot reach would be reported.
Algorithm.
dist[src] = 0, all others10^8.- Repeat
V - 1times: for each edge[u, v, w], ifdist[u] != INFanddist[u] + w < dist[v], setdist[v] = dist[u] + w. - For each edge, if it can still be relaxed, return
[-1]. - Return
dist.
static int[] bellmanFord(int V, int[][] edges, int src) {
int[] dist = new int[V];
Arrays.fill(dist, INF);
dist[src] = 0;
for (int round = 1; round <= V - 1; round++) {
for (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
if (dist[u] != INF && dist[u] + w < dist[v]) dist[v] = dist[u] + w;
}
}
for (int[] e : edges) { // round V: any improvement means a negative cycle
int u = e[0], v = e[1], w = e[2];
if (dist[u] != INF && dist[u] + w < dist[v]) return new int[]{-1};
}
return dist;
}
Complexity. Time O(V · E): V passes over all E edges. Space O(V) for the distance array. For V = 500 and E ≈ 250,000 that is about 1.25 × 10^8 cheap operations, which is acceptable but not fast.
Approach 2: Bellman-Ford with early exit
Intuition. The V - 1 bound is a worst case. Once a round changes nothing, no later round can change anything either, because each round reads only the current dist values and they are identical. So we track whether a round made any update and stop as soon as one is quiet. If the graph has a reachable negative cycle, every round makes an update (by the argument above), so if round V still changes something we report the cycle. This folds the detection round into the main loop.
Algorithm.
dist[src] = 0, all others10^8.- For
round = 1..V: relax every edge, remembering whether anything changed. If nothing changed, returndist. - If the loop finishes, the
V-th round still improved something, so return[-1].
static int[] bellmanFordEarlyExit(int V, int[][] edges, int src) {
int[] dist = new int[V];
Arrays.fill(dist, INF);
dist[src] = 0;
for (int round = 1; round <= V; round++) {
boolean changed = false;
for (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
if (dist[u] != INF && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
changed = true;
}
}
if (!changed) return dist; // a quiet round: every distance is final
}
return new int[]{-1}; // V rounds and still improving
}
Dry run on Example 1 (src = 2), edges in the given order:
| round | 0→1 (5) | 1→0 (3) | 1→2 (-1) | 2→0 (1) | dist after | changed |
|---|---|---|---|---|---|---|
| 1 | skip (0 unreached) | skip | skip | dist[0] = 1 | [1, ∞, 0] | yes |
| 2 | dist[1] = 6 | 9 > 1 | 5 > 0 | 1 = 1 | [1, 6, 0] | yes |
| 3 | 6 = 6 | no | no | no | [1, 6, 0] | no, return |
Approach 1 would run rounds 1 and 2 (that is V - 1) and then a check round, which is the same work here. On a long chain listed in the right order the early exit finishes after two rounds instead of V.
Complexity. Worst case still O(V · E), for example a chain whose edges are listed backwards (the tests include one), where each round advances the frontier by exactly one edge. Best case O(E) when the first round already settles everything. Space O(V).
Edge cases and pitfalls
- Unreached sources. Never relax from a vertex whose distance is still
INF. Besides the false-cycle problem above,INF + wcan produce nonsense like10^8 - 3. - Negative cycle not reachable from
src. It does not affect any distance fromsrc, so the expected output is the normal array. The tests include a cycle2 → 3 → 2of weight-4withsrc = 0. - Negative self-loop. An edge
u → uwith negative weight is a cycle of length one. Ifuis reachable, the answer is[-1]. - Undirected graphs. An undirected edge with negative weight is a negative cycle by itself (
u → v → u). Bellman-Ford is meant for directed graphs; add both directions only when every weight is non-negative. - Edge order matters for speed, not correctness. Different orders give different numbers of rounds before stabilising, but the same final distances.
- Overflow. With
|w| ≤ 1000and at mostV - 1edges on a path, distances stay within about±5 × 10^5, sointis safe. With larger weights uselong.
Related problems
- Djisktra’s Algorithm is faster but needs non-negative weights.
- Floyd warshall algorithm computes all pairs and also detects negative cycles.
- Cheapest flight within K stops runs a limited number of Bellman-Ford rounds to cap the number of edges.
- Network Delay Time can be solved with either Bellman-Ford or Dijkstra.
- Shortest path in DAG handles negative weights in one pass when the graph has no cycles at all.