Overview
Bellman-Ford computes single-source shortest paths even when some edges have negative weights. It relaxes every edge V - 1 times. After round k, all shortest paths that use at most k edges are correct, and since a simple path has at most V - 1 edges, V - 1 rounds are enough.
A V-th round detects negative cycles: if any distance still improves, a cycle with negative total weight is reachable and shortest paths are undefined. Its O(V x E) cost is slower than Dijkstra, but the 'at most k edges' property directly solves problems with a limit on stops.
Every day, each town hears from its neighbors how far they are from the capital and updates its own estimate. After enough days, every town knows its true distance. If some estimates keep dropping forever, a road loop somewhere is paying travelers to drive around it (a negative cycle).
When to use it
- Edge weights can be negative.
- You must detect negative cycles (arbitrage, inconsistent constraints).
- Shortest path with at most K edges or stops.
- Distributed settings where each node only knows its neighbors (distance-vector routing).
Problem patterns it solves
Recognize it when: cheapest route with a limit on stops or edges.
- 787. Cheapest Flights Within K Stops
Recognize it when: some edges reduce the cost.
- 743. Network Delay Time (works but slower)
- Single-source shortest paths with negative edges
Recognize it when: arbitrage, infinite profit loops, inconsistent constraints.
- Currency arbitrage detection
- Difference constraints systems
Where it is used in real software
The RIP protocol is a distributed Bellman-Ford: routers repeatedly share distance tables with neighbors.
Using edge weights of -log(rate), a negative cycle means a sequence of trades that ends with more money than it started.
Systems of difference constraints (x - y <= c) used in scheduling are solved as shortest paths with possible negative weights.
Key terms
- Relaxation round
- One pass over every edge trying dist[u] + w < dist[v].
- V - 1 rounds
- Enough for any simple shortest path.
- Negative cycle
- A cycle whose total weight is negative; distances can decrease forever.
- SPFA
- Queue-based optimization that only relaxes edges from nodes that changed.
How it works, step by step
- 1Initialize
dist[source] = 0; all others Infinity.
- 2Repeat V - 1 times
For every edge (u, v, w): if dist[u] + w < dist[v], update dist[v].
- 3Stop early
If a whole round changes nothing, distances are final.
- 4Check for negative cycles
Run one more round; any improvement means a reachable negative cycle.
- 5For K-stop limits
Run exactly K + 1 rounds and relax from a copy of the previous round's distances.
Negative edge handled correctly
Edges: S->A 4, S->B 5, B->A -3, A->C 2
| Round | Relaxations | dist S, A, B, C |
|---|---|---|
| Init | - | 0, inf, inf, inf |
| 1 | S->A = 4, S->B = 5, B->A: 5 - 3 = 2, A->C: 2 + 2 = 4 | 0, 2, 5, 4 |
| 2 | no improvement | 0, 2, 5, 4 |
| Check | no improvement: no negative cycle | 0, 2, 5, 4 |
NOWRound: Init | Relaxations: - | dist S, A, B, C: 0, inf, inf, inf
The best path to A goes through B even though S->B is longer, thanks to the -3 edge. Dijkstra would have finalized A = 4 too early.
Implementation
function bellmanFord(n, edges, source) { const dist = new Array(n).fill(Infinity); dist[source] = 0; for (let round = 0; round < n - 1; round++) { let changed = false; for (const [u, v, w] of edges) { if (dist[u] !== Infinity && dist[u] + w < dist[v]) { dist[v] = dist[u] + w; changed = true; } } if (!changed) break; } for (const [u, v, w] of edges) { if (dist[u] !== Infinity && dist[u] + w < dist[v]) { return { dist, negativeCycle: true }; } } return { dist, negativeCycle: false };} // 787. Cheapest Flights Within K Stops: exactly k + 1 edge roundsfunction findCheapestPrice(n, flights, src, dst, k) { let dist = new Array(n).fill(Infinity); dist[src] = 0; for (let i = 0; i <= k; i++) { const next = dist.slice(); // use only last round's values for (const [u, v, price] of flights) { if (dist[u] !== Infinity && dist[u] + price < next[v]) next[v] = dist[u] + price; } dist = next; } return dist[dst] === Infinity ? -1 : dist[dst];}Complexity and performance
V - 1 rounds over all edges.
Distance array.
Only K + 1 rounds.
Worst case still O(V x E).
Trade-offs
Slower, but correct with negative weights and able to detect negative cycles.
Bellman-Ford is single-source; Floyd-Warshall computes all pairs in O(V^3).
Variants and related techniques
Only relax edges out of nodes whose distance changed in the previous step.
Uses Bellman-Ford once to reweight edges, then Dijkstra from every node for all-pairs shortest paths in sparse graphs.
Common mistakes
- Updating dist in place for the K-stop variant.
Fix: In-place updates can chain several edges in one round; copy the array each round.
- Adding to Infinity.
Fix: Skip edges where dist[u] is Infinity (critical in Java with MAX_VALUE overflow).
- Reporting distances when a negative cycle exists.
Fix: Distances reachable from the cycle are undefined; report the cycle.
Interview questions
Why are V - 1 rounds enough?
A shortest path without cycles has at most V - 1 edges, and after round k every shortest path with at most k edges has been found.
How does Bellman-Ford detect a negative cycle?
After V - 1 rounds all simple paths are final. If a V-th round still improves a distance, the improvement must come from going around a negative cycle.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 787. Cheapest Flights Within K Stops | Medium | Round-limited relaxation. |
| 743. Network Delay Time | Medium | Compare with Dijkstra. |
| Detect currency arbitrage | Hard | Negative cycle with -log weights. |