Bellman-Ford Algorithm for Shortest Paths
Problem and examples
Given a weighted, directed, and connected graph with V vertices and E edges, the task is to find the shortest distance from a given source vertex S to all other vertices.
Note: If the graph contains a negative weight cycle that is reachable from the source, return an array containing only -1.
| Vertices | Edges | Source | Output | Description |
|---|---|---|---|---|
| 5 | [(0,1,5), (0,2,4), (1,3,3), (2,1,6), (3,2,-2)] | 0 | [0,5,4,8,INF] | Shortest paths from source 0 to all vertices |
| 3 | [(0,1,1), (1,2,-1), (2,0,-1)] | 0 | [-1] | Graph contains a negative weight cycle |
| 4 | [(0,1,1), (0,2,4), (1,2,-2), (2,3,2)] | 0 | [0,1,-1,1] | Graph with negative weights, but no cycle |
| 2 | [(0,1,3)] | 0 | [0,3] | Simple two-node graph |
| 1 | [] | 0 | [0] | Graph with only one node |
How it works
Understanding the Problem
The Bellman-Ford Algorithm is used to find the shortest paths from a single source vertex to all other vertices in a weighted graph. Unlike Dijkstra's algorithm, Bellman-Ford supports negative weight edges and is capable of detecting negative weight cycles — cycles where the total sum of edge weights is negative.
This algorithm is especially useful in scenarios like financial networks or graphs with penalties, where such negative weights naturally occur.
Step-by-Step Solution with Example
Step 1: Initialize the Distance Array
Assume a graph with 5 vertices (numbered 0 to 4) and the following edges:
edges = [
[0, 1, 6],
[0, 2, 7],
[1, 2, 8],
[1, 3, 5],
[1, 4, -4],
[2, 3, -3],
[2, 4, 9],
[3, 1, -2],
[4, 3, 7]
]
source = 0
We initialize a dist[] array such that dist[source] = 0 and all others as Infinity.
Step 2: Relax All Edges V-1 Times
We iterate over all edges V - 1 times (where V is the number of vertices). During each pass, we attempt to "relax" each edge:
- If
dist[u] + weight < dist[v], updatedist[v] = dist[u] + weight.
After each pass, the algorithm slowly propagates the shortest path information throughout the graph.
Step 3: Detect Negative Weight Cycle
After performing V-1 iterations, we perform one extra pass over all edges. If any distance can still be reduced, it means a negative weight cycle exists in the graph.
In that case, the algorithm should return [-1] to indicate the presence of such a cycle.
Step 4: Final Result
If no negative cycles are detected, return the dist[] array, which contains the shortest distances from the source to every other vertex.
[0, 2, 7, 4, -2] // For the given example
Edge Cases
- Graph with no edges: All nodes remain at
Infinitydistance except the source. - Negative edge but no cycle: Bellman-Ford handles it correctly.
- Disconnected graph: Vertices that are not reachable from the source remain at
Infinity. - Negative weight cycle: If a cycle exists that can endlessly decrease the path cost, the algorithm detects it and should return
[-1].
Finally
The Bellman-Ford algorithm is an essential tool when dealing with graphs that include negative edge weights. While it's not as fast as Dijkstra’s algorithm for graphs with only positive weights, its ability to detect negative cycles makes it extremely valuable.
By following a clear step-by-step relaxation process and checking for further improvements in the last iteration, we ensure both correctness and cycle detection. Understanding this approach builds a strong foundation for handling more complex graph problems.
- Initialize a distance array
dist[]of sizeVwith all values asInfinity, exceptdist[S] = 0. - Repeat
V-1times:- For each edge
(u, v, wt)in the graph: - If
dist[u] + wt < dist[v], updatedist[v] = dist[u] + wt.
- For each edge
- For each edge
(u, v, wt), check again:- If
dist[u] + wt < dist[v], return[-1](negative cycle detected).
- If
- Return
dist[]as the final result.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <limits.h>
#define MAXV 100
#define MAXE 1000
void bellmanFord(int V, int E, int edges[][3], int S) {
int dist[MAXV];
for (int i = 0; i < V; i++) dist[i] = INT_MAX;
dist[S] = 0;
for (int i = 1; i < V; i++) {
for (int j = 0; j < E; j++) {
int u = edges[j][0];
int v = edges[j][1];
int wt = edges[j][2];
if (dist[u] != INT_MAX && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt;
}
}
}
for (int j = 0; j < E; j++) {
int u = edges[j][0];
int v = edges[j][1];
int wt = edges[j][2];
if (dist[u] != INT_MAX && dist[u] + wt < dist[v]) {
printf("-1\n");
return;
}
}
for (int i = 0; i < V; i++) {
printf("%d ", dist[i]);
}
printf("\n");
}
int main() {
int edges1[5][3] = {{0,1,5},{0,2,4},{1,3,3},{2,1,6},{3,2,-2}};
printf("Shortest paths:\n");
bellmanFord(5, 5, edges1, 0);
int edges2[3][3] = {{0,1,1},{1,2,-1},{2,0,-1}};
printf("Cycle detection:\n");
bellmanFord(3, 3, edges2, 0);
return 0;
}C++ implementation
#include <iostream>
#include <vector>
using namespace std;
vector<int> bellmanFord(int V, vector<vector<int>>& edges, int S) {
vector<int> dist(V, INT_MAX);
dist[S] = 0;
for (int i = 1; i < V; ++i) {
for (auto& edge : edges) {
int u = edge[0], v = edge[1], wt = edge[2];
if (dist[u] != INT_MAX && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt;
}
}
}
for (auto& edge : edges) {
int u = edge[0], v = edge[1], wt = edge[2];
if (dist[u] != INT_MAX && dist[u] + wt < dist[v]) {
return {-1};
}
}
return dist;
}
int main() {
vector<vector<int>> edges1 = {{0,1,5},{0,2,4},{1,3,3},{2,1,6},{3,2,-2}};
vector<int> result1 = bellmanFord(5, edges1, 0);
cout << "Shortest paths:\n";
for (int d : result1) cout << d << " ";
cout << endl;
vector<vector<int>> edges2 = {{0,1,1},{1,2,-1},{2,0,-1}};
vector<int> result2 = bellmanFord(3, edges2, 0);
cout << "Cycle detection:\n";
for (int d : result2) cout << d << " ";
cout << endl;
return 0;
}Python implementation
def bellman_ford(V, edges, S):
dist = [float('inf')] * V
dist[S] = 0
for _ in range(V - 1):
for u, v, wt in edges:
if dist[u] != float('inf') and dist[u] + wt < dist[v]:
dist[v] = dist[u] + wt
for u, v, wt in edges:
if dist[u] != float('inf') and dist[u] + wt < dist[v]:
return [-1]
return dist
print("Shortest paths:", bellman_ford(5, [[0,1,5],[0,2,4],[1,3,3],[2,1,6],[3,2,-2]], 0))
print("Cycle detection:", bellman_ford(3, [[0,1,1],[1,2,-1],[2,0,-1]], 0))Java implementation
import java.util.*;
public class BellmanFord {
public static int[] bellmanFord(int V, int[][] edges, int S) {
int[] dist = new int[V];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[S] = 0;
for (int i = 1; i < V; i++) {
for (int[] edge : edges) {
int u = edge[0], v = edge[1], wt = edge[2];
if (dist[u] != Integer.MAX_VALUE && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt;
}
}
}
for (int[] edge : edges) {
int u = edge[0], v = edge[1], wt = edge[2];
if (dist[u] != Integer.MAX_VALUE && dist[u] + wt < dist[v]) {
return new int[]{-1};
}
}
return dist;
}
public static void main(String[] args) {
int[][] edges1 = {{0,1,5},{0,2,4},{1,3,3},{2,1,6},{3,2,-2}};
System.out.println("Shortest paths:");
System.out.println(Arrays.toString(bellmanFord(5, edges1, 0)));
int[][] edges2 = {{0,1,1},{1,2,-1},{2,0,-1}};
System.out.println("Cycle detection:");
System.out.println(Arrays.toString(bellmanFord(3, edges2, 0)));
}
}JavaScript implementation
function bellmanFord(V, edges, S) {
const dist = Array(V).fill(Infinity);
dist[S] = 0;
for (let i = 1; i < V; i++) {
for (const [u, v, wt] of edges) {
if (dist[u] !== Infinity && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt;
}
}
}
for (const [u, v, wt] of edges) {
if (dist[u] !== Infinity && dist[u] + wt < dist[v]) {
return [-1];
}
}
return dist;
}
const edges1 = [[0,1,5],[0,2,4],[1,3,3],[2,1,6],[3,2,-2]];
console.log("Shortest paths:", bellmanFord(5, edges1, 0));
const edges2 = [[0,1,1],[1,2,-1],[2,0,-1]];
console.log("Cycle detection:", bellmanFord(3, edges2, 0));Go implementation
package main
import (
"fmt"
"math"
)
func bellmanFord(V int, edges [][3]int, S int) []int {
dist := make([]int, V)
for i := range dist {
dist[i] = math.MaxInt32
}
dist[S] = 0
for i := 1; i < V; i++ {
for _, edge := range edges {
u, v, wt := edge[0], edge[1], edge[2]
if dist[u] != math.MaxInt32 && dist[u]+wt < dist[v] {
dist[v] = dist[u] + wt
}
}
}
for _, edge := range edges {
u, v, wt := edge[0], edge[1], edge[2]
if dist[u] != math.MaxInt32 && dist[u]+wt < dist[v] {
return []int{-1}
}
}
return dist
}
func main() {
edges1 := [][3]int{{0, 1, 5}, {0, 2, 4}, {1, 3, 3}, {2, 1, 6}, {3, 2, -2}}
fmt.Println("Shortest paths:", bellmanFord(5, edges1, 0))
edges2 := [][3]int{{0, 1, 1}, {1, 2, -1}, {2, 0, -1}}
fmt.Println("Cycle detection:", bellmanFord(3, edges2, 0))
}Rust implementation
fn bellman_ford(v: usize, edges: &Vec<(usize, usize, i32)>, s: usize) -> Vec<i32> {
let mut dist = vec![i32::MAX; v];
dist[s] = 0;
for _ in 0..v - 1 {
for &(u, vtx, wt) in edges.iter() {
if dist[u] != i32::MAX && dist[u] + wt < dist[vtx] {
dist[vtx] = dist[u] + wt;
}
}
}
for &(u, vtx, wt) in edges.iter() {
if dist[u] != i32::MAX && dist[u] + wt < dist[vtx] {
return vec![-1];
}
}
dist
}
fn main() {
let edges1 = vec![(0,1,5),(0,2,4),(1,3,3),(2,1,6),(3,2,-2)];
println!("Shortest paths: {:?}", bellman_ford(5, &edges1, 0));
let edges2 = vec![(0,1,1),(1,2,-1),(2,0,-1)];
println!("Cycle detection: {:?}", bellman_ford(3, &edges2, 0));
}Kotlin implementation
fun bellmanFord(V: Int, edges: Array<IntArray>, S: Int): IntArray {
val dist = IntArray(V) { Int.MAX_VALUE }
dist[S] = 0
for (i in 1 until V) {
for (edge in edges) {
val (u, v, wt) = edge
if (dist[u] != Int.MAX_VALUE && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt
}
}
}
for (edge in edges) {
val (u, v, wt) = edge
if (dist[u] != Int.MAX_VALUE && dist[u] + wt < dist[v]) {
return intArrayOf(-1)
}
}
return dist
}
fun main() {
val edges1 = arrayOf(intArrayOf(0,1,5), intArrayOf(0,2,4), intArrayOf(1,3,3), intArrayOf(2,1,6), intArrayOf(3,2,-2))
println("Shortest paths: " + bellmanFord(5, edges1, 0).joinToString())
val edges2 = arrayOf(intArrayOf(0,1,1), intArrayOf(1,2,-1), intArrayOf(2,0,-1))
println("Cycle detection: " + bellmanFord(3, edges2, 0).joinToString())
}Swift implementation
func bellmanFord(V: Int, edges: [(Int, Int, Int)], S: Int) -> [Int] {
var dist = [Int](repeating: Int.max, count: V)
dist[S] = 0
for _ in 1..<V {
for (u, v, wt) in edges {
if dist[u] != Int.max && dist[u] + wt < dist[v] {
dist[v] = dist[u] + wt
}
}
}
for (u, v, wt) in edges {
if dist[u] != Int.max && dist[u] + wt < dist[v] {
return [-1]
}
}
return dist
}
let edges1 = [(0,1,5),(0,2,4),(1,3,3),(2,1,6),(3,2,-2)]
print("Shortest paths:", bellmanFord(V: 5, edges: edges1, S: 0))
let edges2 = [(0,1,1),(1,2,-1),(2,0,-1)]
print("Cycle detection:", bellmanFord(V: 3, edges: edges2, S: 0))TypeScript implementation
function bellmanFord(V: number, edges: [number, number, number][], S: number): number[] {
const dist: number[] = new Array(V).fill(Infinity);
dist[S] = 0;
for (let i = 1; i < V; i++) {
for (const [u, v, wt] of edges) {
if (dist[u] !== Infinity && dist[u] + wt < dist[v]) {
dist[v] = dist[u] + wt;
}
}
}
for (const [u, v, wt] of edges) {
if (dist[u] !== Infinity && dist[u] + wt < dist[v]) {
return [-1];
}
}
return dist;
}
const edges1: [number, number, number][] = [[0,1,5],[0,2,4],[1,3,3],[2,1,6],[3,2,-2]];
console.log("Shortest paths:", bellmanFord(5, edges1, 0));
const edges2: [number, number, number][] = [[0,1,1],[1,2,-1],[2,0,-1]];
console.log("Cycle detection:", bellmanFord(3, edges2, 0));