Bellman-Ford Algorithm
Description
The Bellman-Ford algorithm finds the shortest paths from a source vertex to all other vertices in a weighted graph. Unlike Dijkstra's algorithm, it can handle graphs with negative weight edges and detect negative weight cycles. The algorithm works by repeatedly relaxing all edges V-1 times, where V is the number of vertices.
- Can detect negative cycles in the graph
- Works with both positive and negative edge weights
- Guarantees shortest paths in absence of negative cycles
- Simpler but slower than Dijkstra's algorithm
History

The Bellman-Ford algorithm was independently discovered by Alfonso Shimbel (1955), Edward F. Moore (1957), and Richard Bellman (1958). However, it is most commonly named after Richard Bellman and Lester Ford Jr., who published it in 1958 and 1956 respectively. Richard Bellman made significant contributions to the field of dynamic programming, which is a key concept used in this algorithm. Lester Ford Jr. developed the algorithm while working on network flow problems at the RAND Corporation. His work was focused on solving transportation and logistics challenges, which naturally led to the development of efficient path-finding algorithms. The algorithm was later refined and popularized by Richard Bellman, who provided a more rigorous mathematical analysis and showed its connection to dynamic programming principles. The algorithm's ability to handle negative edge weights made it particularly valuable for applications beyond simple path finding, such as in financial arbitrage detection and network routing protocols. Today, it remains a fundamental algorithm in computer science, particularly in networking where it formed the basis for the RIP (Routing Information Protocol) used in early internet routing. The GOAT of dynamic programming.
Visualization
Select a source vertex to start Bellman-Ford algorithm
How It Works
- Initialize distances to all vertices as infinite except the source (distance = 0)
- Repeat V-1 times:
- For each edge (u, v) with weight w:
- If distance[u] + w < distance[v]:
- Update distance[v] = distance[u] + w
- Check for negative weight cycles:
- If any distance can be reduced further
- Graph contains a negative weight cycle
Implementation
def bellman_ford(graph, source):
# Initialize distances and predecessors
distances = {vertex: float('infinity') for vertex in graph}
predecessors = {vertex: None for vertex in graph}
distances[source] = 0
# Relax edges |V| - 1 times
for _ in range(len(graph) - 1):
for u in graph:
for v, weight in graph[u].items():
if distances[u] + weight < distances[v]:
distances[v] = distances[u] + weight
predecessors[v] = u
# Check for negative weight cycles
for u in graph:
for v, weight in graph[u].items():
if distances[u] + weight < distances[v]:
raise ValueError("Graph contains a negative weight cycle")
return distances, predecessors
#include <vector>
#include <limits>
#include <stdexcept>
struct Edge {
int src, dest;
int weight;
};
class BellmanFord {
public:
static vector<int> FindShortestPaths(const vector<Edge>& edges,
int V, int source) {
vector<int> distances(V, numeric_limits<int>::max());
distances[source] = 0;
// Relax edges |V| - 1 times
for (int i = 0; i < V - 1; i++) {
for (const Edge& edge : edges) {
if (distances[edge.src] != numeric_limits<int>::max() &&
distances[edge.src] + edge.weight < distances[edge.dest]) {
distances[edge.dest] = distances[edge.src] + edge.weight;
}
}
}
// Check for negative weight cycles
for (const Edge& edge : edges) {
if (distances[edge.src] != numeric_limits<int>::max() &&
distances[edge.src] + edge.weight < distances[edge.dest]) {
throw runtime_error("Graph contains negative weight cycle");
}
}
return distances;
}
};
public class BellmanFord
{
public class Edge
{
public int Source { get; set; }
public int Destination { get; set; }
public int Weight { get; set; }
}
public static Dictionary<int, int> FindShortestPaths(List<Edge> edges,
int vertexCount,
int source)
{
var distances = new Dictionary<int, int>();
// Initialize distances
for (int i = 0; i < vertexCount; i++)
{
distances[i] = int.MaxValue;
}
distances[source] = 0;
// Relax edges |V| - 1 times
for (int i = 0; i < vertexCount - 1; i++)
{
foreach (var edge in edges)
{
if (distances[edge.Source] != int.MaxValue &&
distances[edge.Source] + edge.Weight < distances[edge.Destination])
{
distances[edge.Destination] = distances[edge.Source] + edge.Weight;
}
}
}
// Check for negative weight cycles
foreach (var edge in edges)
{
if (distances[edge.Source] != int.MaxValue &&
distances[edge.Source] + edge.Weight < distances[edge.Destination])
{
throw new InvalidOperationException(
"Graph contains a negative weight cycle");
}
}
return distances;
}
}
Complexity Analysis
Operation | Time Complexity | Space Complexity |
---|---|---|
Worst Case | O(VE) | O(V) |
Average Case | O(VE) | O(V) |
Best Case | O(E) | O(V) |
Where V is the number of vertices and E is the number of edges in the graph.
Advantages and Disadvantages
Advantages
- Handles negative edge weights
- Detects negative cycles
- Simple to implement
- Works with any graph structure
- Guarantees shortest paths if no negative cycles
Disadvantages
- Slower than Dijkstra's algorithm
- O(VE) complexity can be high for dense graphs
- Not suitable for graphs with negative cycles
- Requires all edges to be processed V-1 times
- Higher memory usage than some alternatives
Applications
- Network routing protocols (like RIP)
- Currency exchange and arbitrage detection
- Traffic routing with potential negative costs
- Network delay analysis
- Constraint satisfaction problems