Bellman-Ford Algorithm — Shortest Paths with Negative Weights
- Bellman-Ford relaxes all edges V-1 times, finding shortest paths even with negative weights in O(VE).
- A Vth relaxation pass that still improves a distance proves a negative cycle exists.
- Dijkstra is faster but only correct for non-negative weights; Bellman-Ford handles negative edges.
Imagine you're planning a road trip and some roads give you fuel credits (negative cost) instead of costing you money. Dijkstra's algorithm would panic — it assumes every road costs you something. Bellman-Ford, on the other hand, is the calm navigator who says 'let me check every single road, multiple times, just to be sure I've found the cheapest route — even if some roads pay YOU to drive them.' It also warns you if there's a loop of fuel-credit roads that would let you drive forever for free, which would make any shortest-path answer meaningless.
Financial trading systems use graph algorithms to find arbitrage opportunities — sequences of currency exchanges that yield profit. GPS routing engines handle toll roads, ferry routes, and restricted zones. Network packet routing protocols like RIP (Routing Information Protocol) propagate cost updates across distributed nodes. In every one of these systems, the edge weights on a graph can be negative. That single reality invalidates Dijkstra's algorithm entirely, and it's the reason Bellman-Ford exists.
The core problem Bellman-Ford solves is single-source shortest paths in a weighted directed graph where edge weights can be negative. Dijkstra's greedy approach assumes that once a node is 'settled' its shortest distance is final — a guarantee that collapses the moment a future negative edge could have produced a cheaper path. Bellman-Ford abandons the greedy assumption and instead performs exhaustive relaxation: it checks every edge, repeatedly, until it's mathematically certain no cheaper path exists. As a bonus, it can detect negative-weight cycles — loops in the graph where traversing the cycle keeps reducing your total cost to negative infinity, making shortest paths undefined.
By the end of this article you'll understand exactly why Bellman-Ford performs V-1 relaxation passes and not V or V-2, how to implement it correctly in Java with proper negative-cycle detection, where it outperforms Dijkstra in practice, what the subtle off-by-one bugs look like in interview code, and how production systems like distributed routing protocols derive their design directly from this algorithm's properties.
What is Bellman-Ford? — Plain English
Bellman-Ford finds the shortest path from a source node to all other nodes in a weighted graph, even when some edge weights are negative. Dijkstra's algorithm fails with negative edges because it assumes that once a node is finalized, its distance cannot improve — negative edges can always make a path shorter. Bellman-Ford handles this by relaxing all edges V-1 times. Why V-1? The shortest path between any two nodes in a graph with V nodes uses at most V-1 edges (otherwise it would visit a node twice, forming a cycle). After V-1 relaxation passes, all shortest paths are found. A V-th pass that still relaxes an edge signals a negative cycle — a loop whose total weight is negative, making the shortest path undefined.
How Bellman-Ford Works — Step by Step
Algorithm on a graph with V vertices and E edges:
- Initialize dist[source] = 0, dist[all others] = infinity.
- Repeat V-1 times:
- a. For each edge (u, v, weight) in the edge list:
- b. If dist[u] + weight < dist[v]: relax → dist[v] = dist[u] + weight.
- Negative cycle detection: do one more pass over all edges.
- a. If any edge (u,v,w) still satisfies dist[u] + w < dist[v], a negative cycle exists.
- Return the dist array (and predecessors if path reconstruction is needed).
Worked Example — 5-Node Graph with Negative Edge
Graph edges (u,v,weight): (0,1,4),(0,2,5),(1,2,-3),(1,3,6),(2,4,2),(3,4,1),(4,3,-2). Source=0.
Initial: dist=[0,inf,inf,inf,inf].
- (0,1,4): dist[1]=min(inf,0+4)=4.
- (0,2,5): dist[2]=min(inf,0+5)=5.
- (1,2,-3): dist[2]=min(5,4-3)=1.
- (1,3,6): dist[3]=min(inf,4+6)=10.
- (2,4,2): dist[4]=min(inf,1+2)=3.
- (3,4,1): dist[4]=min(3,10+1)=3 (no change).
- (4,3,-2): dist[3]=min(10,3-2)=1. dist after pass 1: [0,4,1,1,3].
- (1,3,6): dist[3]=min(1,4+6)=1 no change.
- (4,3,-2): dist[3]=min(1,3-2)=1 no change.
- All others: no improvement. dist unchanged.
Passes 3,4: no changes. Final dist=[0,4,1,1,3].
Implementation
Bellman-Ford iterates over the edge list V-1 times, relaxing each edge. The edge list representation (list of (u,v,weight) tuples) is simpler to use than adjacency lists for this algorithm. The V-th pass detects negative cycles. Time complexity O(VE) makes it slower than Dijkstra's O((V+E) log V), but it handles negative weights. Space complexity is O(V) for the distance array plus O(E) for the edge list.
def bellman_ford(num_vertices, edges, source): """ edges: list of (u, v, weight) Returns (dist, has_negative_cycle) """ INF = float('inf') dist = [INF] * num_vertices dist[source] = 0 # Relax all edges V-1 times for _ in range(num_vertices - 1): updated = False for u, v, w in edges: if dist[u] != INF and dist[u] + w < dist[v]: dist[v] = dist[u] + w updated = True if not updated: # Early exit if no relaxation occurred break # Detect negative cycles (V-th pass) has_neg_cycle = False for u, v, w in edges: if dist[u] != INF and dist[u] + w < dist[v]: has_neg_cycle = True break return dist, has_neg_cycle # Example: 4-node graph edges = [(0,1,4),(0,2,5),(1,2,-3),(1,3,6),(2,3,2)] dist, neg = bellman_ford(4, edges, 0) print(dist) # [0, 4, 1, 3] print(neg) # False
False
| Feature / Aspect | Bellman-Ford | Dijkstra |
|---|---|---|
| Time Complexity | O(V × E) | O((V + E) log V) with binary heap |
| Space Complexity | O(V) for distances + O(E) for edge list | O(V) for distances + O(V) for priority queue |
| Negative Edge Weights | ✅ Fully supported | ❌ Produces incorrect results |
| Negative Cycle Detection | ✅ Built-in with V-th pass | ❌ Not supported — undefined behaviour |
| Graph Type | Directed (adaptable to undirected) | Directed and undirected |
| Implementation Complexity | Simple — flat edge-list loop | Moderate — requires priority queue |
| Distributed Systems Use | ✅ Foundation of RIP, distance-vector routing | ❌ Requires global state — not distributed-friendly |
| Dense Graph Performance | Poor — O(V³) on complete graph | Good — O(V² log V) on complete graph |
| Sparse Graph Performance | Good when E ≈ V | Excellent when E ≈ V |
| All-Pairs Shortest Paths | O(V² × E) — very slow | Better via Johnson's Algorithm (run BF once, Dijkstra V times) |
🎯 Key Takeaways
- Bellman-Ford relaxes all edges V-1 times, finding shortest paths even with negative weights in O(VE).
- A Vth relaxation pass that still improves a distance proves a negative cycle exists.
- Dijkstra is faster but only correct for non-negative weights; Bellman-Ford handles negative edges.
⚠ Common Mistakes to Avoid
Interview Questions on This Topic
- QWhy does Bellman-Ford need V-1 iterations?
- QHow does Bellman-Ford detect negative cycles?
- QWhat is the time complexity of Bellman-Ford?
Frequently Asked Questions
Why does Bellman-Ford need exactly V-1 passes?
The shortest path with no repeated vertices uses at most V-1 edges. Each pass of Bellman-Ford guarantees that all shortest paths using at most k edges are correctly computed after k passes. After V-1 passes, all shortest paths (which use at most V-1 edges) are found. A Vth pass that still finds improvement implies a cycle in the path, which must be a negative cycle.
When should I use Bellman-Ford instead of Dijkstra?
Use Bellman-Ford when: (1) the graph has negative weight edges, (2) you need to detect negative cycles, or (3) the graph is represented as an edge list. Use Dijkstra when all weights are non-negative and you need faster performance O((V+E) log V). In most competitive programming and interview problems, Dijkstra is preferred unless negative weights are specified.
Can Bellman-Ford find the shortest path in a graph with a negative cycle?
No. If a negative cycle is reachable from the source, the shortest path to some nodes is negative infinity (you can loop the negative cycle infinitely). Bellman-Ford detects the negative cycle but cannot return meaningful distances for nodes reachable through it. The algorithm returns a flag indicating cycle presence.
Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.