Senior 7 min · March 05, 2026

Bellman-Ford — Disconnected Negative Cycles Miss Detection

Bellman-Ford skips negative cycles unreachable from the source—arbitrage loops in other subgraphs go undetected.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Bellman-Ford computes single-source shortest paths even with negative edge weights.
  • It relaxes all edges V-1 times to guarantee optimal distances.
  • A V-th pass that still improves a distance signals a negative cycle.
  • Works on directed graphs; adapts to undirected by replacing each edge with two directed edges.
  • Time complexity O(V·E) — slower than Dijkstra's O((V+E) log V) but handles negative weights.
  • Big production insight: when used for currency arbitrage, a negative cycle means infinite profit — but the algorithm only detects it, it doesn't stop the loop from being exploited.
Plain-English First

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.

Production Insight
Real-world routing protocols (RIP) use Bellman-Ford-like mechanisms. They suffer from the 'count to infinity' problem because they don't have global knowledge and must rely on neighbor updates.
A single negative weight from a misconfigured link cost can propagate incorrect routes across the entire network.
Rule: in distributed systems, Bellman-Ford must be paired with split horizon or poison reverse to prevent loops.
Key Takeaway
Bellman-Ford trades speed for correctness with negative weights.
It guarantees optimal distances after V-1 edge relaxations.
Negative cycles are detected by an extra pass — but only if reachable from the source.

How Bellman-Ford Works — Step by Step

  1. Initialize dist[source] = 0, dist[all others] = infinity.
  2. Repeat V-1 times:
  3. a. For each edge (u, v, weight) in the edge list:
  4. b. If dist[u] + weight < dist[v]: relax → dist[v] = dist[u] + weight.
  5. Negative cycle detection: do one more pass over all edges.
  6. a. If any edge (u,v,w) still satisfies dist[u] + w < dist[v], a negative cycle exists.
  7. Return the dist array (and predecessors if path reconstruction is needed).
Production Insight
Early exit can cut runtime dramatically: if no relaxation happens in a pass, the algorithm halves its work on sparse graphs.
But early exit can mask a negative cycle if the cycle is only reachable via edges that haven't been relaxed yet — rare but possible.
Rule: only break early after V-1 passes for correctness, but use it anytime for performance analysis.
Key Takeaway
V-1 passes guarantee correctness for all shortest paths.
Early exit speeds up the average case but does not affect correctness.
The V-th pass is mandatory for cycle detection — never skip it.

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].

Pass 1 (relax all edges)
  • (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].
Pass 2
  • (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].

Production Insight
Notice how one negative edge (–3) changed the distances for two other nodes in the same pass. This propagation effect is why Bellman-Ford needs multiple passes.
In production, if your graph has a long chain of negative edges, the algorithm may need all V-1 passes to converge.
Rule: the propagation distance per pass equals at most one edge length of the path.
Key Takeaway
Negative edges cause changes that ripple through the graph within the same pass.
If no updates happen in a pass, the algorithm can early exit — the result remains correct.
Always test on graphs with multiple negative edges to ensure passes are sufficient.

Implementation in Python

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.

bellman_ford.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
Output
[0, 4, 1, 3]
False
Production Insight
Using float('inf') is safe for distances but can cause performance issues if graph is huge — every float comparison is cheap, but the overhead of Python lists for millions of edges may be high.
For production in Python, consider using arrays from 'array' module or NumPy for large V.
Rule: always check for overflow when using integer types in other languages.
Key Takeaway
Edge list representation is the most memory-efficient for Bellman-Ford.
Early exit reduces runtime but does not skip the cycle detection pass.
The code above is the canonical version — adapt it carefully for large-scale use.

Implementation in Java — with Integer Overflow Protection

Java implementation requires care with initial distances. Use Long.MAX_VALUE to avoid overflow when adding weights. The algorithm is nearly identical to Python, but type safety and explicit loops make it easier to spot off-by-one errors.

BellmanFord.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package io.thecodeforge.algorithm;

import java.util.*;

public class BellmanFord {
    public static class Edge {
        int u, v, weight;
        public Edge(int u, int v, int weight) {
            this.u = u; this.v = v; this.weight = weight;
        }
    }

    public static Pair<long[], Boolean> shortestPath(int n, List<Edge> edges, int source) {
        long[] dist = new long[n];
        Arrays.fill(dist, Long.MAX_VALUE);
        dist[source] = 0;

        // Relax V-1 times
        for (int i = 0; i < n - 1; i++) {
            boolean updated = false;
            for (Edge e : edges) {
                if (dist[e.u] != Long.MAX_VALUE && dist[e.u] + e.weight < dist[e.v]) {
                    dist[e.v] = dist[e.u] + e.weight;
                    updated = true;
                }
            }
            if (!updated) break;
        }

        // Cycle detection
        boolean hasCycle = false;
        for (Edge e : edges) {
            if (dist[e.u] != Long.MAX_VALUE && dist[e.u] + e.weight < dist[e.v]) {
                hasCycle = true;
                break;
            }
        }
        return new Pair<>(dist, hasCycle);
    }

    public static void main(String[] args) {
        List<Edge> edges = Arrays.asList(
            new Edge(0,1,4),
            new Edge(0,2,5),
            new Edge(1,2,-3),
            new Edge(1,3,6),
            new Edge(2,3,2)
        );
        var result = shortestPath(4, edges, 0);
        System.out.println(Arrays.toString(result.first));
        System.out.println(result.second);
    }
}
Output
[0, 4, 1, 3]
false
Production Insight
Integer overflow is a silent killer. Using Integer.MAX_VALUE and adding a positive weight wraps to negative, making every edge look like a relaxation. This is a common interview gotcha.
The fix: use long[] and Long.MAX_VALUE with a guard if(dist[u] != MAX).
Rule: when implementing Bellman-Ford, always use the widest safe integer type (long in Java, Long.MAX_VALUE) and never rely on overflow behaviour.
Key Takeaway
Java requires explicit overflow protection — use Long.MAX_VALUE.
The early exit and cycle detection logic is the same as Python.
Always test with graphs that have integer.MAX_VALUE distances to ensure guard works.

C++ Implementation with Edge Struct

C++ implementation uses a struct Edge to hold the source, destination, and weight. We use vector<Edge> to store all edges and vector<long long> for distances to avoid overflow. The LLONG_MAX sentinel prevents integer overflow when adding weights. This implementation follows the same V-1 relaxation pattern and V-th pass for cycle detection.

bellman_ford.cppCPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = LLONG_MAX;

struct Edge {
    int u, v, weight;
};

pair<vector<ll>, bool> bellmanFord(int n, vector<Edge>& edges, int source) {
    vector<ll> dist(n, INF);
    dist[source] = 0;

    // Relax all edges V-1 times
    for (int i = 0; i < n - 1; ++i) {
        bool updated = false;
        for (const Edge& e : edges) {
            if (dist[e.u] != INF && dist[e.u] + e.weight < dist[e.v]) {
                dist[e.v] = dist[e.u] + e.weight;
                updated = true;
            }
        }
        if (!updated) break;
    }

    // Negative cycle detection
    bool hasNegativeCycle = false;
    for (const Edge& e : edges) {
        if (dist[e.u] != INF && dist[e.u] + e.weight < dist[e.v]) {
            hasNegativeCycle = true;
            break;
        }
    }

    return {dist, hasNegativeCycle};
}

int main() {
    vector<Edge> edges = {{0,1,4}, {0,2,5}, {1,2,-3}, {1,3,6}, {2,3,2}};
    auto [dist, neg] = bellmanFord(4, edges, 0);
    for (ll d : dist) cout << d << " ";
    cout << endl << (neg ? "true" : "false") << endl;
    return 0;
}
Output
0 4 1 3
false
Production Insight
C++ code often runs in competitive programming where edge counts can be large. Using vector<Edge> keeps memory contiguous and cache-friendly. The LLONG_MAX sentinel is safe as long as you never add a positive weight to it — the guard prevents that. In production, you may want to use std::optional<string> for error propagation instead of a pair.
Key Takeaway
C++ implementation mirrors the Python/Java logic but uses LLONG_MAX and explicit struct. Always guard against overflow and use long long for distances.

SPFA — Queue-Based Bellman-Ford Variant

The Shortest Path Faster Algorithm (SPFA) is an optimization of Bellman-Ford that uses a queue to process only vertices whose distance changed in the previous iteration. Instead of blindly iterating over all edges V-1 times, SPFA pushes the vertex v onto a queue whenever its distance is updated. The queue ensures that only edges from recently updated vertices are examined, which often achieves O(kE) average time, where k is usually small (k ≈ 2 for random graphs). However, SPFA's worst-case complexity remains O(VE) and can be triggered by adversarial graph structures. SPFA also simplifies negative cycle detection: if any vertex is relaxed more than V times, a reachable negative cycle exists. While not fundamentally different from Bellman-Ford, SPFA is popular in competitive programming for its simplicity and speed on typical inputs. Production systems should still rely on the standard V-1 pass approach for provable guarantees, but SPFA is a useful tool for rapid prototyping.

Production Insight
SPFA's average-case speed makes it tempting for production, but adversarial inputs can degrade it to O(VE) and cause unpredictable latency. In financial systems where latency matters, prefer the deterministic O(VE) of standard Bellman-Ford. The queue also adds memory overhead. Rule: use SPFA only when the input size is moderate and worst-case guarantees are not critical.
Key Takeaway
SPFA uses a queue to skip unnecessary relaxation, average O(kE) but worst-case O(VE). Implement cycle detection by counting relaxations per node — if a node is relaxed V times, a negative cycle exists.

Advantages and Disadvantages of Bellman-Ford

Advantages: - Handles negative edge weights correctly — essential for many real-world problems. - Built-in negative cycle detection via one extra pass. - Simple to implement using an edge list; no complex data structures required. - Works on distributed systems (e.g., RIP routing protocol). - Can be used as a preprocessing step for Johnson's algorithm (all-pairs shortest paths). - Early exit optimization improves average-case performance.

Disadvantages: - Time complexity O(VE) is slow on dense graphs (E ~ V²), making it impractical for large graphs. - Only detects negative cycles reachable from the source — requires super-source hack for full detection. - Not suitable for undirected graphs with negative edges (creates 2-edge negative cycles). - Integer overflow is a common bug in implementations without proper sentinel. - No path reconstruction unless predecessors are explicitly stored. - Early exit can mask undiscovered negative cycles if the cycle is not yet reachable.

Understanding these trade-offs helps you choose the right algorithm: Dijkstra for no negatives, Bellman-Ford for sparse graphs with negatives, and Johnson's when you need all-pairs with negatives.

Production Insight
In practice, Bellman-Ford is rarely used outside of specific niches (routing protocols, small financial graphs, Johnson's preprocessing). For large graphs with negative edges, consider using Johnson's algorithm (one run of Bellman-Ford plus V runs of Dijkstra) or the Floyd-Warshall algorithm (O(V³)) for all-pairs. The key production lesson: always verify the graph size and density before committing to Bellman-Ford.
Key Takeaway
Bellman-Ford's strength is negative weight handling and cycle detection, but its O(VE) complexity limits its use. Pair it with a super-source for global cycle detection.

Practice Problems

Sharpen your Bellman-Ford skills with these curated problems that test understanding of negative edges, cycle detection, and optimization.

  1. LeetCode 743 — Network Delay Time (Medium) – Single-source shortest path with non-negative weights; a good warm-up to compare Dijkstra vs Bellman-Ford.
  2. LeetCode 787 — Cheapest Flights Within K Stops (Medium) – Bellman-Ford variant that limits the number of edges (passes).
  3. CSES — Shortest Routes I – Directed weighted graph with no negative cycles; test basic single-source shortest path.
  4. CSES — Shortest Routes II – All-pairs shortest paths with negative edges; requires Floyd-Warshall or Johnson's.
  5. Codeforces — 1000F: Conveyor (or similar) – Problems focusing on negative cycle detection and extraction.
  6. Codeforces — 1338A: Powered Addition (not directly, but requires understanding of increments) – Better: search for 'Bellman-Ford' tag on Codeforces for recent contests.
  7. GeeksforGeeks — Negative Weight Cycle – Straightforward detection problem.

Each problem reinforces a specific aspect: basic relaxation, pass limit, cycle detection, or early exit. After solving them, you'll be ready for interview questions and production scenarios.

Production Insight
Competitive programming problems often hide negative cycles in unexpected components. Always add a super-source in practice problems to avoid missing cycles. The LeetCode 787 K-Stops problem directly mirrors Bellman-Ford with a maximum number of edges, which is exactly how RIP routing works with hop count limits.
Key Takeaway
Practice on problems that combine negative weights with edge limits or full-graph cycle detection to internalize Bellman-Ford's nuances.

Step-by-Step Edge Relaxation Visualization

The following diagram shows the first two passes of Bellman-Ford on the 5-node example graph. Each step highlights which edges are relaxed and how distances change. The initial state is dist = [0, ∞, ∞, ∞, ∞]. After Pass 1, we see distances propagate from the source. After Pass 2, the negative edge (1,2,-3) continues to improve dist[2] indirectly through the chain. Later passes see no changes, confirming convergence.

Production Insight
In production, visualizing distance propagation helps debug why certain nodes take many passes to converge. If a node's distance keeps improving late into the passes, it may indicate a long chain of negative edges. For large graphs, consider logging the number of updates per pass to detect unexpected behavior.
Key Takeaway
The step-by-step state array shows how distances propagate and converge. Negative edges cause immediate improvements in the same pass, but propagation continues until all paths are found.

Visualizing a Negative Weight Cycle

A negative weight cycle is a directed cycle whose total weight sum is negative. If such a cycle is reachable from the source, the shortest path is undefined — you can loop the cycle infinitely to reduce the distance toward negative infinity. The diagram below illustrates a simple negative cycle: A→B with weight -2, B→C with weight 1, C→A with weight -1. Total sum = -2 + 1 - 1 = -2 (< 0). Starting from node A, traversing the cycle once reduces distance by 2, forever. Bellman-Ford detects this because after V-1 passes, the edge B→A still relaxes.

Production Insight
In financial systems, a negative cycle corresponds to an arbitrage opportunity — a sequence of trades that yields profit without risk. Bellman-Ford detects the cycle, but exploiting it in real-time requires careful risk management. In network routing, a negative cycle manifests as a routing loop, which must be broken by protocol mechanisms like split horizon. Rule: always treat negative cycle detection as a critical alert; do not ignore it merely because the source doesn't reach it (add super-source).
Key Takeaway
A negative weight cycle makes shortest paths meaningless. The cycle is detected by the V-th pass, but only if reachable from the source. Always use a super-source to detect cycles in disconnected components.

Negative Cycle Detection — Deep Dive

A negative cycle is a cycle whose total weight is negative. If such a cycle is reachable from the source, the shortest path to nodes affected by it is -infinity — you can loop the cycle to reduce cost arbitrarily. Bellman-Ford detects this by performing one extra relaxation pass after V-1 passes. If any edge still relaxes, a negative cycle exists.

But beware: the cycle must be reachable from the source. A cycle in a disconnected component will not be detected unless you use a super-source. Also, the detection only tells you that a cycle exists, not which nodes are affected. To find affected nodes, run a BFS/DFS from any edge that relaxed during the V-th pass.

Production Insight
In distributed systems like RIP, negative cycles manifest as routing loops. The 'count to infinity' problem arises because each router only knows its neighbors' distances — a form of Bellman-Ford without global knowledge.
To mitigate, engineers use 'split horizon' and 'route poisoning'.
Rule: in any production system using Bellman-Ford-like algorithms, always implement cycle detection at the protocol level, not just at individual nodes.
Key Takeaway
Detection requires reachability — disconnected cycles are invisible.
If you suspect cycles in any component, add a super-source.
The V-th pass flags the existence, not the extent — mark all nodes part of any cycle by tracing back from relaxing edges.
How to Classify Negative Cycle Scenarios
IfCycle reachable from source
UseBellman-Ford detects it: distances to some nodes become -infinity arbitrarily.
IfCycle not reachable from source
UseV-th pass shows no relaxation. You must use super-source or run from every component.
IfMultiple cycles, some reachable, some not
UseOnly reachable ones are flagged. Unreachable cycles remain hidden.
IfGraph has negative edges but no cycle
UseBellman-Ford works correctly and returns finite shortest paths.
● Production incidentPOST-MORTEMseverity: high

Silent Output with Unreachable Negative Cycles

Symptom
A team runs Bellman-Ford on a large financial graph. The algorithm reports no negative cycles, but traders find an arbitrage loop in the Pacific region. The system missed it because the source was in Europe and the cycle was in a disconnected subgraph.
Assumption
Engineers assumed Bellman-Ford would detect any negative cycle in the entire graph automatically.
Root cause
Bellman-Ford only detects cycles reachable from the source. If the cycle is in a separate component, the algorithm never traverses it. The V-th pass sees no improvement because distances to those nodes remain infinity.
Fix
Add a dummy super-source with zero-weight edges to every vertex, run Bellman-Ford from it, then perform the V-th pass. This ensures all cycles are reachable and detected. This is exactly what Johnson's algorithm does as preprocessing.
Key lesson
  • Bellman-Ford only detects negative cycles reachable from the source.
  • To scan the whole graph, use a super-source with zero edges to all vertices.
  • Never trust a negative-cycle negative result if nodes may be disconnected from the source.
Production debug guideSymptom → Action mapping for common failures4 entries
Symptom · 01
Distances come out as huge negative numbers after running
Fix
Check for integer overflow: if using Integer.MAX_VALUE, adding a weight wraps around. Use Long.MAX_VALUE with explicit guard.
Symptom · 02
No improvement detected on V-th pass, but you suspect a negative cycle exists
Fix
Verify the cycle is reachable from source. Add a super-source and rerun.
Symptom · 03
Algorithm takes suspiciously long (near O(V·E) instead of early exit)
Fix
Check density: V·E might be enormous. Consider topological ordering if graph is a DAG (0-1 BFS) or switch to Dijkstra if no negative edges.
Symptom · 04
Shortest paths seem correct but one node is off by a constant
Fix
Probable bug: forgot to initialize dist[source] = 0, or used inf comparisons that never trigger. Verify all distances are finite for reachable nodes.
★ Bellman-Ford Quick Debug CommandsMental checklist and commands for verifying correctness and catching cycle bugs in your implementation.
Distance array contains unexpected infinities
Immediate action
Check source initialization — did you set dist[source]=0?
Commands
print('dist source:', dist[source])
print('edges:', edges[:5]) # check first few edges
Fix now
Ensure the edge list contains all edges and source is correct. re-run with debug prints after each pass.
Negative cycle detection fails to trigger+
Immediate action
Check reachability: verify that the cycle nodes have finite distances before V-th pass.
Commands
print('Nodes reachable:', [i for i, d in enumerate(dist) if d != INF])
for (u,v,w) in edges: if dist[u]!=INF and dist[u]+w < dist[v]: print('cycle edge:', u,v,w)
Fix now
Add super-source technique: create virtual vertex connected to all others with weight 0, then run Bellman-Ford again.
Algorithm runs full V-1 passes even when graph is sparse+
Immediate action
Add early exit: if no relaxation happens in a pass, break.
Commands
updated = any(dist[u]+w < dist[v] for u,v,w in edges)
if not updated: break
Fix now
Implement the early exit flag; it reduces runtime for graphs with no negative edges.
Bellman-Ford vs Dijkstra's Algorithm
Feature / AspectBellman-FordDijkstra
Time ComplexityO(V × E)O((V + E) log V) with binary heap
Space ComplexityO(V) for distances + O(E) for edge listO(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 TypeDirected (adaptable to undirected)Directed and undirected
Implementation ComplexitySimple — flat edge-list loopModerate — requires priority queue
Distributed Systems Use✅ Foundation of RIP, distance-vector routing❌ Requires global state — not distributed-friendly
Dense Graph PerformancePoor — O(V³) on complete graphGood — O(V² log V) on complete graph
Sparse Graph PerformanceGood when E ≈ VExcellent when E ≈ V
All-Pairs Shortest PathsO(V² × E) — very slowBetter via Johnson's Algorithm (run BF once, Dijkstra V times)

Key takeaways

1
Bellman-Ford relaxes all edges V-1 times, finding shortest paths even with negative weights in O(VE).
2
A Vth relaxation pass that still improves a distance proves a negative cycle exists (if reachable from source).
3
Dijkstra is faster but only correct for non-negative weights; Bellman-Ford handles negative edges.
4
Use a super-source to detect cycles in disconnected components.
5
Always guard against integer overflow when implementing in Java or C++.

Common mistakes to avoid

4 patterns
×

Running exactly V passes for relaxation and using the last pass for detection

Symptom
The algorithm appears to work on graphs without negative cycles, but silently skips negative-cycle detection entirely. Any graph with a negative cycle returns plausible-looking but meaningless distances.
Fix
Use a loop for (pass = 0; pass < numVertices - 1; pass++) for relaxation, then a separate loop after it for detection — never conflate the two.
×

Using Integer.MAX_VALUE as initial distance sentinel and adding a positive weight to it

Symptom
Integer overflow causes the sum to wrap around to a large negative number. Suddenly every edge looks like it relaxes, and the output is garbage with no error thrown.
Fix
Use Long.MAX_VALUE with a long[] distance array, or add an explicit guard if (distanceTo[source] != Long.MAX_VALUE) before attempting relaxation.
×

Declaring 'no negative cycle' simply because no relaxation fires on the V-th pass from your specific source

Symptom
If the negative cycle is in a disconnected component or unreachable from your source, Bellman-Ford won't see it. The algorithm reports no cycle, but the cycle still exists elsewhere.
Fix
For full-graph negative-cycle detection, add a dummy super-source vertex with zero-weight edges to every other vertex, run Bellman-Ford from that super-source, and perform the V-th pass check. This is exactly what Johnson's Algorithm does as its preprocessing step.
×

Forgetting to mark predecessors or reconstruct paths

Symptom
You get distances but cannot answer 'which path gives this distance?' Many implementations skip storing predecessors, making path reconstruction impossible.
Fix
Add a prev[] array initialized to -1. Each time you relax dist[v], set prev[v] = u. After the algorithm, walk back from target to source using prev.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Why does Bellman-Ford need exactly V-1 iterations?
Q02SENIOR
How does Bellman-Ford detect negative cycles?
Q03JUNIOR
What is the time complexity of Bellman-Ford?
Q04SENIOR
How would you modify Bellman-Ford to detect all vertices that are part o...
Q01 of 04SENIOR

Why does Bellman-Ford need exactly V-1 iterations?

ANSWER
The shortest path in a graph with V vertices, assuming no negative cycles, uses at most V-1 edges. A path with V edges would visit V+1 vertices, which means at least one vertex is repeated, forming a cycle. If that cycle has zero or positive weight, removing it never worsens the path; if it has negative weight, the shortest path is undefined. Therefore, after V-1 relaxation passes, the shortest path is guaranteed to be found. One more pass (V-th) is used to detect if any negative cycle exists — if an edge still relaxes, a negative cycle is present.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Why does Bellman-Ford need exactly V-1 passes?
02
When should I use Bellman-Ford instead of Dijkstra?
03
Can Bellman-Ford find the shortest path in a graph with a negative cycle?
04
How do I adapt Bellman-Ford for undirected graphs?
05
What is the early-exit optimization in Bellman-Ford?
🔥

That's Graphs. Mark it forged?

7 min read · try the examples if you haven't

Previous
Dijkstra Shortest Path Algorithm
5 / 17 · Graphs
Next
Floyd-Warshall Algorithm