10.6 Detecting Negative Cycles with Bellman-Ford
In the previous recipe, Bellman-Ford was used to compute shortest paths in graphs that contain negative edge weights.
10.6 Detecting Negative Cycles with Bellman-Ford
In the previous recipe, Bellman-Ford was used to compute shortest paths in graphs that contain negative edge weights. The algorithm included an additional pass that detected negative cycles, but the detection itself deserves a closer look.
Negative cycles are fundamentally different from ordinary graph structures. A shortest path normally represents a minimum cost route between two vertices. A negative cycle destroys that concept. If traversing a cycle decreases total cost, then repeatedly traversing the cycle decreases the path cost indefinitely.
In such graphs, shortest paths cease to exist.
This recipe focuses on identifying negative cycles and determining which vertices are affected by them.
Problem
Given a directed weighted graph, determine whether a negative cycle is reachable from the source.
For example:
A --1--> B
^ |
| |
| v
C <-- -4--
1
The cycle:
A -> B -> C -> A
has total cost:
1 + (-4) + 1 = -2
Each traversal decreases the path cost by two.
No finite shortest path exists.
The goal is to detect this condition.
Solution
Bellman-Ford computes shortest paths using:
V - 1
relaxation passes.
If another improvement remains possible after those passes, a negative cycle must exist.
package main
import "fmt"
type Edge struct {
From int
To int
Weight int
}
func hasNegativeCycle(vertices int, edges []Edge, source int) bool {
const INF = int(1e18)
dist := make([]int, vertices)
for i := range dist {
dist[i] = INF
}
dist[source] = 0
for i := 0; i < vertices-1; i++ {
for _, edge := range edges {
if dist[edge.From] == INF {
continue
}
newDistance := dist[edge.From] + edge.Weight
if newDistance < dist[edge.To] {
dist[edge.To] = newDistance
}
}
}
for _, edge := range edges {
if dist[edge.From] == INF {
continue
}
if dist[edge.From]+edge.Weight < dist[edge.To] {
return true
}
}
return false
}
func main() {
edges := []Edge{
{0, 1, 1},
{1, 2, -4},
{2, 0, 1},
}
fmt.Println(hasNegativeCycle(3, edges, 0))
}
Output:
true
Why the Detection Works
Suppose a graph contains:
0 -> 1 = 3
1 -> 2 = 2
The shortest path to vertex 2 contains at most:
V - 1
edges.
After enough relaxation passes, the optimal distance becomes known.
Further passes produce no changes.
A graph with a negative cycle behaves differently.
Consider:
0 -> 1 = 1
1 -> 2 = -3
2 -> 0 = 1
The cycle cost is:
1 + (-3) + 1 = -1
After one traversal:
distance[0] = -1
After two traversals:
distance[0] = -2
After three traversals:
distance[0] = -3
Distances continue decreasing forever.
The extra Bellman-Ford pass detects precisely this behavior.
If relaxation remains possible, some cycle must still be generating improvements.
Since all shortest paths should already have converged, that cycle must be negative.
Finding the Actual Cycle
Detecting the existence of a negative cycle is often sufficient.
Some applications require the cycle itself.
Bellman-Ford can reconstruct it by recording predecessors.
parent[edge.To] = edge.From
Whenever a relaxation occurs.
During the final pass, remember the last updated vertex.
changedVertex = edge.To
If a negative cycle exists, repeatedly following predecessors eventually enters the cycle.
A common implementation is:
for i := 0; i < vertices; i++ {
changedVertex = parent[changedVertex]
}
After walking backward V times, the vertex must lie inside the cycle.
The cycle can then be reconstructed by continuing until the starting vertex reappears.
This technique appears frequently in competitive programming and graph-analysis systems.
Reachable Versus Unreachable Negative Cycles
A subtle detail often surprises newcomers.
Consider:
Source Component
0 -> 1 -> 2
Disconnected Component
3 -> 4 -> 5 -> 3
Suppose the disconnected component contains a negative cycle.
3 -> 4 = -1
4 -> 5 = -1
5 -> 3 = -1
Bellman-Ford starting from vertex 0 reports:
No negative cycle
Why?
Because the cycle cannot be reached from the source.
Shortest-path computation only concerns vertices reachable from the starting point.
The unreachable cycle has no effect on any path originating at the source.
This explains the guard:
if dist[edge.From] == INF {
continue
}
Only reachable vertices participate in relaxation.
Propagating Negative Infinity
Some applications require more than cycle detection.
Consider:
A -> B -> C
^
|
D
Suppose a negative cycle reaches B.
Then:
distance[B] = -∞
Because the cycle can be traversed indefinitely.
Any vertex reachable from B also becomes:
distance = -∞
since the cycle can be repeated before continuing.
Many graph systems therefore perform an additional traversal after cycle detection.
All vertices influenced by a negative cycle are marked.
This distinction is important in:
- Constraint solving
- Financial arbitrage analysis
- Program analysis
- Route optimization systems
Discussion
Negative cycles represent inconsistencies.
In shortest-path problems, they imply that the optimization objective has no lower bound.
In financial networks, they represent arbitrage opportunities.
In constraint systems, they indicate contradictory requirements.
In scheduling systems, they often reveal invalid dependencies.
Bellman-Ford detects these inconsistencies naturally because the algorithm repeatedly attempts to improve distances.
Normal graphs eventually stabilize.
Graphs containing negative cycles do not.
This difference is the foundation of the detection mechanism.
Complexity
The detection pass adds only one extra scan of all edges.
| Operation | Complexity |
|---|---|
| Bellman-Ford relaxation | O(VE) |
| Negative-cycle detection | O(E) |
| Cycle reconstruction | O(V) |
| Memory usage | O(V) |
The detection cost is negligible compared to the relaxation phase.
Common Mistakes
Do not assume every negative edge produces a negative cycle.
A graph may contain many negative edges and still have perfectly valid shortest paths.
Do not confuse a negative cycle with a cycle whose total weight is zero.
A zero-cost cycle does not cause distances to decrease indefinitely.
Do not remove the reachability check.
Unreachable negative cycles should not influence source-based shortest-path calculations.
Do not stop after detecting a cycle if downstream vertices must be identified. Additional propagation may be required.
Practical Applications
Negative-cycle detection appears in:
- Currency arbitrage systems
- Foreign-exchange trading networks
- Difference constraint systems
- Task scheduling validation
- Transportation optimization
- Resource allocation systems
- Compiler data-flow analysis
- Graph consistency checking
In many of these domains, discovering the inconsistency is more valuable than computing shortest paths.
Takeaway
A negative cycle indicates that path costs can decrease without bound. Bellman-Ford detects this condition by performing one additional relaxation pass after shortest paths should already have converged. If any edge can still improve a distance, a reachable negative cycle exists. This simple observation transforms Bellman-Ford from a shortest-path algorithm into a powerful graph validation tool.