Why Dijkstra Fails on Negative Edges
Dijkstra is greedy: once it finalises a vertex's distance, it never revisits it. That relies on an assumption — that adding more edges can only make a path longer.
A negative edge breaks it. A vertex finalised early might later be reachable more cheaply via a negative edge, but Dijkstra has already moved on. Load Has a negative edge and watch Bellman-Ford improve a distance in a later pass. Exactly the update Dijkstra would have missed.
Relax every edge V − 1 times
Bellman-Ford makes no greedy commitment. It simply relaxes every edge, repeatedly:
Why V−1 passes? A shortest path can contain at most V−1 edges (any more would revisit a vertex, forming a cycle). Each pass guarantees correctness for paths one edge longer, so V−1 passes settle every possible path.
This brute-force honesty costs O(V·E) — much slower than Dijkstra's O(E log V).
Detecting negative cycles
This is Bellman-Ford's distinctive capability, and the reason it is still used despite being slower.
If a cycle's total weight is negative, going round it again always reduces the distance. There is no shortest path — the answer is negative infinity.
The detection is elegant: after V−1 rounds every genuine shortest path has been found. So if one more round still improves something, a negative cycle must be reachable. That is the final loop in the code above.
To find the cycle itself rather than merely detect it: record a parent for each vertex. And when the extra round relaxes an edge, walk the parent chain backwards V times to land inside the cycle. Then trace round it.
Note the phrase "reachable from source". A negative cycle in a disconnected part of the graph does not affect the answer and will not be detected from that source.
Why Dijkstra cannot do this: it finalises each vertex once, on the assumption that no later path can be shorter. A negative edge breaks that assumption silently, so Dijkstra returns a wrong answer rather than an error — which is worse than failing.
When Negative Weights Are Real
They sound artificial until you meet them: financial transactions with gains and losses, chemical reactions with energy release, game scoring with penalties and bonuses. Or any cost model where some moves refund you.
Related algorithms worth knowing: Floyd-Warshall computes all-pairs shortest paths in O(V³) and also tolerates negative edges; Johnson's algorithm reweights a graph with Bellman-Ford so Dijkstra can then run on it safely.
Why V−1 rounds
A shortest path in a graph with V vertices contains at most V−1 edges. Any more would repeat a vertex, and repeating a vertex means a cycle. This cannot help unless it is negative.
Each round of relaxation guarantees that all shortest paths using one more edge than before are correct. So after round 1 all one-edge shortest paths are settled. After round 2 all two-edge paths, and after V−1 rounds every possible shortest path is found.
That gives O(V × E), which is much worse than Dijkstra's O((V+E) log V). The changed flag helps in practice — most graphs converge well before V−1 rounds — and the worst case stands.
| Algorithm | Weights | Complexity | Detects negative cycles |
|---|
| BFS | Unweighted | O(V+E) | N/A |
| Dijkstra | Non-negative | O((V+E) log V) | No |
| Bellman-Ford | Any | O(VE) | Yes |
| Floyd-Warshall | Any, all pairs | O(V³) | Yes |
| Johnson | Any, all pairs, sparse | O(V² log V + VE) | Yes |
Things to try with Bellman-Ford and Negative Weights
- Run the negative-edge graph. Watch a distance get improved in a later pass. The exact case Dijkstra gets wrong.
- Count the passes. V−1 of them, each relaxing every single edge whether or not it helps.