Bellman–Ford
Bellman-Ford finds the cheapest path from one node to every other node, even when some edges have negative cost. It is the patient sibling of Dijkstra: no clever queue, no greedy picks - it just relaxes every edge, up to V-1 times, and that patience makes it honest about negative weights. As a bonus, one extra pass tells you whether the graph has a negative cycle, where 'cheapest' stops meaning anything. This relax-everything idea once ran the early internet: RIP routers are nodes doing Bellman-Ford on each other.
Watch every edge relax
Press play - or drag the timeline and step through it yourself.Find the cheapest path from A to every node. One edge is negative: C→D costs -4. No queue, no priorities - just relax all 7 edges, again and again, in a fixed order.
Complexity
A group chat of delivery deals
You post a package from your city, A, and five friends want to know the cheapest cost for it to reach them. Nobody sees the whole map - there is only a list of courier routes with prices. So the chat runs rounds: every round, every route is checked once, asking 'best cost into my start city, plus my fee - is that cheaper for the city I end in?'. One route is a promo that pays 4 back for using it. A greedy planner would lock answers in early and miss the promo, but the rounds keep re-checking everything, so the promo's saving spreads to every city behind it. When a whole round changes nothing, the prices are final.
How it works, step by step
Set the start's distance to 0 and every other node to infinity (not reached yet).
Walk the edge list in a fixed order. For each edge u→v with weight w: if `dist[u] + w < dist[v]`, write the smaller value. This check is called relaxing the edge.
One full sweep over all edges is one iteration. Each iteration lets the best-known costs travel at least one edge further from the start.
Repeat up to V-1 times. A shortest path can use at most V-1 edges, so that is always enough - no matter how unlucky the edge order is.
If an iteration improves nothing, stop early. A second identical sweep would see the same numbers and change nothing either.
Safety check: run one extra iteration. If anything still improves, the graph has a negative cycle and 'shortest path' has no meaning.
The code, in JavaScript
The whole algorithm: V-1 sweeps over the edge list, plus the early-exit flag. This is the graph from the animation - with this edge order it settles in one sweep; a worse order just needs more sweeps, never a different answer.
function bellmanFord(nodes, edges, start) {
const dist = Object.fromEntries(nodes.map((n) => [n, Infinity]));
dist[start] = 0;
// A shortest path uses at most V-1 edges, so V-1 sweeps always suffice.
for (let i = 0; i < nodes.length - 1; i++) {
let improved = false;
for (const [from, to, w] of edges) {
// Relax: can from's best cost plus this edge beat to's best?
// Infinity + w is still Infinity, so unreached nodes offer nothing.
if (dist[from] + w < dist[to]) {
dist[to] = dist[from] + w;
improved = true;
}
}
if (!improved) break; // a full sweep changed nothing → we are done
}
return dist;
}
const edges = [
["A", "B", 3], ["A", "C", 9], ["B", "D", 5],
["C", "D", -4], // negative edge: D is cheapest via C
["D", "E", 2], ["D", "F", 6], ["E", "F", 3],
];
bellmanFord(["A", "B", "C", "D", "E", "F"], edges, "A");
// → { A: 0, B: 3, C: 9, D: 5, E: 7, F: 10 }Dry run: Bellman-Ford from node A
The same steps the visualizer plays, written as a table. Generated by running the real algorithm - not written by hand.
| Step | Iteration | What happened |
|---|---|---|
| 1 | 1 | Improve B: ∞ → 3 via A. |
| 2 | 1 | Improve C: ∞ → 9 via A. |
| 3 | 2 | Improve D: ∞ → 8 via B. |
| 4 | 2 | Improve D: 8 → 5 via C. The -4 edge pays off. Dijkstra had already locked D in at 8 - and would have shipped the wrong answer. |
| 5 | 2 | Improve E: ∞ → 7 via D. |
| 6 | 2 | Improve F: ∞ → 11 via D. |
| 7 | 2 | Improve F: 11 → 10 via E. F's best incoming edge re-points from D→F to E→F. |
| 8 | 3 | Relax B→D: 3 + 5 = 8 is not better than 5. No change. |
| 9 | 3 | Relax C→D: 9 - 4 = 5 is not better than 5. No change. |
| 10 | 3 | Relax D→E: 5 + 2 = 7 is not better than 7. No change. |
| 11 | 3 | Relax D→F: 5 + 6 = 11 is not better than 10. No change. |
| 12 | 3 | Relax E→F: 7 + 3 = 10 is not better than 10. No change. |
| 13 | 3 | Relax A→B: 0 + 3 = 3 is not better than 3. No change. |
| 14 | 3 | Relax A→C: 0 + 9 = 9 is not better than 9. No change. |
| 15 | 3 | Iteration 3 relaxed all 7 edges and improved nothing. Safe to stop: another pass would see the exact same numbers, so nothing can ever change again. |
Good choice when…
- Some edges are negative - refunds, cashback, energy regained downhill. Dijkstra's greedy promise breaks there; Bellman-Ford does not care about the sign.
- You need to detect negative cycles: currency arbitrage, broken cost models, 'this constraint system has no solution'.
- The setting is distributed and each node only talks to neighbours - RIP routing is Bellman-Ford run by routers gossiping their distance tables.
- All you have is a flat edge list. No adjacency structure, no priority queue - the whole algorithm is ten lines.
Bad choice when…
- Every weight is non-negative and speed matters. Dijkstra with a heap is O(E log V) against O(V·E) - on a big graph that is milliseconds against minutes.
- The graph is unweighted - BFS already gives shortest paths in O(V+E), with no arithmetic at all.
- The graph has no cycles (a DAG) - one relax pass in topological order beats V-1 sweeps and handles negative edges too.
Common mistakes
- It relaxes edges, not nodes. There is no queue and no visiting order - people carry over their Dijkstra mental model and add one, which either breaks correctness on negatives or quietly rebuilds Dijkstra.
- V-1 iterations is the worst case, not the plan. With the early-exit flag most graphs settle in a few sweeps - forget the flag and every run pays the worst case.
- A negative edge is fine; a negative cycle is fatal - one more lap is always cheaper, so 'shortest' stops existing. On untrusted input, always run the one extra detection pass.
- `Infinity + w` is still `Infinity` in JavaScript, so unreached nodes offer nothing. Swap Infinity for a big number like 1e9 and `1e9 + w` suddenly wins comparisons - inventing paths out of unreachable nodes.
Bellman–Ford vs. its closest relatives
| Algorithm | Best | Average | Worst | Space | Stable |
|---|---|---|---|---|---|
| Bellman–Fordthis page | O(E) | O(V·E) | O(V·E) | O(V) | - |
| Dijkstra's Algorithm | O(E log V) | O(E log V) | O(E log V) | O(V) | - |
| Breadth-First Search | O(V + E) | O(V + E) | O(V + E) | O(V) | - |
| Topological Sort | O(V + E) | O(V + E) | O(V + E) | O(V) | - |