GeeksforGeeks Medium

Bellman–Ford Algorithm

Bellman–Ford Algorithm is a GFG problem (Medium). It solves the bellman ford shortest path problem: the shortest distance from one source vertex to every other vertex in a weighted directed graph, and unlike Dijkstra it works when edges have negative weights.

  • The input is a vertex count V, a list of directed edges [u, v, w], and a source src.
  • It returns the distance to each vertex, with unreachable vertices left at infinity.
  • If the graph contains a negative cycle reachable from the source, no shortest path exists, because going round the cycle again is always cheaper. The algorithm reports that instead of returning distances.

The cost is O(V·E), which is slower than Dijkstra's O(E log V). Negative weights are what you pay that for.

Constraints
  • 1 <= V <= 500
  • 0 <= E <= 10⁴
  • -10⁴ <= weight <= 10⁴
  • Edge weights may be negative; a negative cycle is reported rather than solved
graphshortest-pathdpnegative-weights
Open on GeeksforGeeks ↗
02

Intuition

Dijkstra settles the nearest unfinished vertex and never looks at it again, which is only safe when no edge can lower a distance later. One negative edge breaks that, so Bellman-Ford gives up on clever ordering entirely and just relaxes every edge, over and over.

That plainness buys two guarantees:

  • Correct after V - 1 passes. After k full passes every shortest path using at most k edges is right, and a shortest path never repeats a vertex, so it has at most V - 1 edges.
  • Free cycle detection. Since V - 1 passes are provably enough, a V-th pass can change nothing in an honest graph. If it does, there is a negative cycle.
How to spot this pattern

Reach for Bellman-Ford when edge weights can be negative, or when the question is whether a negative cycle exists at all, such as currency arbitrage. If every weight is non-negative, Dijkstra is strictly faster. If you need distances between every pair rather than from one source, Floyd-Warshall is the O(V³) answer.

03

Approach

Try it first

Before reading on, work a small bellman ford algorithm example by hand: take a four-vertex chain 0→1→2→3 and relax the edges in the order 2→3, 1→2, 0→1. Count how many passes it takes for the distance to reach vertex 3, and you will see why the bound is a number of passes rather than a clever order.

1

Start every distance at infinity but the source

Set dist[src] = 0 and all the rest to infinity. No priority queue and no visited set appear anywhere, and that plainness is exactly what lets negative weights be handled: nothing is ever declared final early.

2

Relax every edge, V-1 times over

A pass walks the whole edge list and, for each [u, v, w], lowers dist[v] to dist[u] + w when that is better. The order of edges inside a pass does not matter, because correctness comes from how many passes run, not from their sequence.

3

Never relax out of an unreachable vertex

Only use an edge when dist[u] is not still infinity:

  • Python: inf + w stays infinite and is harmless.
  • C++ and Java: a large sentinel integer is used instead, and adding a negative weight to it overflows into a small number that floods the array with invented paths.
4

Negative cycle detection with one more pass

Run pass number V. If any edge still relaxes, some route can be made cheaper forever by looping, so report the negative cycle instead of returning distances.

5

Stop early when a pass changes nothing

Track whether any distance moved during a pass and break out if none did, because further passes cannot change anything either. The worst case stays O(V·E), but most real graphs settle long before the bound.

04

Bellman–Ford Algorithm solution in Python | C++ | Java

▶1def bellman_ford(n, edges, src):
▶2 INF = float("inf")
▶3 dist = [INF] * n
▶4 dist[src] = 0
▶5 
▶6 for _ in range(n - 1):
▶7 changed = False
▶8 for u, v, w in edges:
▶9 if dist[u] != INF and dist[u] + w < dist[v]:
▶10 dist[v] = dist[u] + w
▶11 changed = True
▶12 if not changed:
▶13 break
▶14 
▶15 for u, v, w in edges:
▶16 if dist[u] != INF and dist[u] + w < dist[v]:
▶17 return None
▶18 return dist
41−21301234dist0v0∞v1∞v2∞v3∞v4source 0 at 0, rest infinite
dist[0, ∞, ∞, ∞, ∞]start
edges5relaxed each pass
Start. Only the source has a known distance. Everything else is infinite, which means "no route found yet". There is no priority queue and no visited set: Bellman-Ford never declares a vertex finished early, and that is exactly what lets negative edges be handled.
41−21301234dist0v04v1∞v2∞v3∞v4pass 1: v1 drops to 4
edge0 → 1weight 4
via v00 + 4= 4
dist[1]4was ∞
Edge 0 → 1 offers 0 + 4 = 4, which beats ∞, so the distance to vertex 1 comes down.
41−21301234dist0v04v11v2∞v3∞v4pass 1: v2 drops to 1
edge0 → 2weight 1
via v00 + 1= 1
dist[2]1was ∞
Edge 0 → 2 offers 0 + 1 = 1, which beats ∞, so the distance to vertex 2 comes down.
41−21301234dist0v0-1v11v2∞v3∞v4pass 1: v1 drops to -1
edge2 → 1weight -2
via v21 + -2= -1
dist[1]-1was 4
Edge 2 → 1 offers 1 + -2 = -1, which beats 4, so the distance to vertex 1 comes down. The weight is negative, which is precisely the case Dijkstra would have got wrong by settling vertex 1 too early.
41−21301234dist0v0-1v11v20v3∞v4pass 1: v3 drops to 0
edge1 → 3weight 1
via v1-1 + 1= 0
dist[3]0was ∞
Edge 1 → 3 offers -1 + 1 = 0, which beats ∞, so the distance to vertex 3 comes down.
41−21301234dist0v0-1v11v20v33v4pass 1: v4 drops to 3
edge3 → 4weight 3
via v30 + 3= 3
dist[4]3was ∞
Edge 3 → 4 offers 0 + 3 = 3, which beats ∞, so the distance to vertex 4 comes down.
41−21301234dist0v0-1v11v20v33v4pass 1 done
pass1of at most 4
dist[0, -1, 1, 0, 3]after this pass
Pass 1 complete. Every shortest path using at most 1 edge is now correct. A shortest path never repeats a vertex, so it spans at most 4 edges, which is why 4 passes are enough.
41−21301234dist0v0-1v11v20v33v4pass 2 changed nothing
pass2no distance moved
dist[0, -1, 1, 0, 3]final
A whole pass improved nothing. Every later pass reads the same distances and the same edges, so it would change nothing either. The loop breaks out early; the worst case is still V−1 passes, but most graphs settle well before that.
41−21301234dist0v0-1v11v20v33v4extra pass: nothing improves
checkno edge relaxesno negative cycle
One more pass over every edge. Nothing improves, which is what an honest graph must do once 4 passes have run. Had any edge still relaxed here, it would have proved a negative cycle.
41−21301234dist0v0-1v11v20v33v4return the distances
dist[0, -1, 1, 0, 3]from v0
Return [0, -1, 1, 0, 3]. Every vertex has its shortest distance from vertex 0. The cost was 4 passes over 5 edges, which is the O(V·E) price of tolerating negative weights.
05

Common pitfalls

Relaxing out of a vertex that is still unreachable

✗ Wrong
if dist[u] + w < dist[v]:
✓ Right
if dist[u] != INF and dist[u] + w < dist[v]:

Python's inf + w stays infinite, so it happens to be safe there, but C++ and Java use a large sentinel integer. Adding a negative weight to it gives a small number that looks like a real distance, and the bogus value then spreads to the rest of the graph.

Skipping the extra detection pass

✗ Wrong
return dist
✓ Right
for u, v, w in edges:
    if dist[u] != INF and dist[u] + w < dist[v]:
        return None
return dist

After V - 1 passes every genuine shortest path is settled, so a further improvement can only come from a cycle of negative total weight. Without the check you return numbers that no path actually achieves.

Running the passes a vertex short

✗ Wrong
for _ in range(n - 2):
✓ Right
for _ in range(n - 1):

A shortest path can span V - 1 edges, and a pass only guarantees one more edge's worth of correctness. On a chain through every vertex, one pass too few leaves the last distance unsettled.

06

Edge cases

A negative cycle reachable from the source

The V-th pass still improves an edge, so the algorithm reports the cycle; the distances are meaningless because they can be driven down forever.

A vertex with no route from the source

Its distance stays at infinity, and the guard stops any edge leaving it from inventing a path.

A negative edge that is not part of a cycle

Handled normally. Later passes lower the distances that the negative edge improves, which is the case Dijkstra gets wrong.

07

Complexity

Time
O(V·E)
Space
O(V)
The bellman ford algorithm time complexity is O(V·E): each of the V-1 passes walks all E edges, so the work is O(V·E), plus one more pass to test for a negative cycle. Only the distance array is stored, giving O(V) space. Dijkstra is faster at O(E log V) but needs every weight to be non-negative.