<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. DSA
  3. Graphs
All lessons in this course

Lesson 36 of 50 14 minAdvanced

Bellman-Ford and Floyd-Warshall

Handle negative edge weights and detect negative cycles with Bellman-Ford, and compute the shortest distance between every pair of vertices with Floyd-Warshall.

Dijkstra is fast but has two limits: weights must not be negative, and it answers “from one source”. This lesson covers the two classic algorithms for the other cases. Both are simpler to write than Dijkstra; they are just slower.

When are weights negative?

Distances and times are never negative, but costs can be: a route that earns a refund, a crane move that recovers energy, a currency exchange that gains money (exchange rates become negative weights after taking logarithms). And sometimes negative cycles are exactly what you want to detect: a loop of trades that makes money for nothing is an arbitrage opportunity, or a bug in the data.

Bellman-Ford

Forget priority queues: relax every edge, and repeat the whole pass V − 1 times. After pass k, every shortest path that uses at most k edges is correct. A shortest path never needs more than V − 1 edges (it visits each vertex at most once), so V − 1 passes are enough. If anything still improves in an extra pass, there must be a negative cycle: a loop you could go round for ever, getting cheaper each time.

Interactive

Bellman-Ford and Floyd-Warshall

One-way links with costs; A → C is −4 (a negative cost, like a credit). Each round relaxes every edge once, in the order listed below. With 5 nodes, 4 rounds are always enough, unless there is a negative cycle.

25-44326SABCD
Edge order: C→D 2, A→D 5, A→C -4, B→C 4, B→A 3, S→B 2, S→A 6
SABCD
start0∞∞∞∞
Start: S = 0, everything else ∞.
BellmanFord.cs
string[] names = { "S", "A", "B", "C", "D" };var edges = new List<(int From, int To, int W)>{    (3, 4, 2), (1, 4, 5), (1, 3, -4), (2, 3, 4), (2, 1, 3), (0, 2, 2), (0, 1, 6)}; var dist = BellmanFord(names.Length, edges, 0);Console.WriteLine(dist is null ? "Negative cycle!" : string.Join(" ", names.Zip(dist, (n, d) => $"{n}:{d}"))); edges.Add((4, 1, -6));                           // D → A: closes the loop A → C → D → A (−8)dist = BellmanFord(names.Length, edges, 0);Console.WriteLine(dist is null ? "Negative cycle!" : string.Join(" ", names.Zip(dist, (n, d) => $"{n}:{d}"))); static long[]? BellmanFord(int n, List<(int From, int To, int W)> edges, int source){    var d = new long[n];    Array.Fill(d, long.MaxValue);    d[source] = 0;    for (int pass = 1; pass < n; pass++)                       // V − 1 passes    {        bool changed = false;        foreach (var (u, v, w) in edges)            if (d[u] != long.MaxValue && d[u] + w < d[v]) { d[v] = d[u] + w; changed = true; }        if (!changed) return d;                                // nothing moved: done early    }    foreach (var (u, v, w) in edges)                           // one extra pass        if (d[u] != long.MaxValue && d[u] + w < d[v]) return null;   // still improving: negative cycle    return d;}
Output
S:0 A:5 B:2 C:1 D:3
Negative cycle!

Cost: O(V · E), much slower than Dijkstra on big graphs, but it handles negative weights and tells you when the question has no answer. Note the != long.MaxValue check: “∞ + a negative weight” must stay ∞, not wrap around to a huge negative number.

Floyd-Warshall: every pair at once

Sometimes you need a full distance table: the travel time between every pair of sites. Floyd-Warshall builds it with three nested loops. The idea: allow the vertices as stopovers one at a time. After considering stopover k, d[i, j] is the shortest route from i to j that only stops at vertices 0…k. The update is one line: is going via k better?

FloydWarshall.cs
const int INF = int.MaxValue / 2;                 // half, so INF + INF does not overflowint n = 4;var d = new int[n, n];for (int i = 0; i < n; i++)    for (int j = 0; j < n; j++)        d[i, j] = i == j ? 0 : INF; foreach (var (a, b, w) in new[] { (0, 1, 3), (0, 3, 7), (1, 0, 8), (1, 2, 2), (2, 0, 5), (2, 3, 1), (3, 0, 2) })    d[a, b] = w; for (int k = 0; k < n; k++)                       // allow k as a stopover    for (int i = 0; i < n; i++)        for (int j = 0; j < n; j++)            if (d[i, k] + d[k, j] < d[i, j])                d[i, j] = d[i, k] + d[k, j]; for (int i = 0; i < n; i++){    var row = new List<string>();    for (int j = 0; j < n; j++) row.Add(d[i, j] >= INF ? "∞" : d[i, j].ToString());    Console.WriteLine(string.Join("\t", row));}
Output
0	3	5	6
5	0	2	3
3	6	0	1
2	5	7	0

O(V³) time and O(V²) memory: perfect for a few hundred vertices, impossible for a road network of millions. It also works with negative edges; a negative number on the diagonal (d[i, i] < 0) reveals a negative cycle.

AlgorithmQuestionNegative weightsTime
BFSOne source, unweighted–O(V + E)
DijkstraOne sourceNoO((V + E) log V)
Bellman-FordOne sourceYes, detects negative cyclesO(V · E)
Floyd-WarshallAll pairsYes, detects negative cyclesO(V³)
Quick check

Bellman-Ford runs on a graph with 6 vertices. How many passes over all edges does it need at most (before the negative-cycle check)?

Quick check

Why is INF set to int.MaxValue / 2 in Floyd-Warshall?

Practice

Use Floyd-Warshall on the undirected site graph from this module (roads A–B 4, A–D 2, B–E 3, B–C 6, D–E 5, C–E 2, C–F 3, E–G 4, D–G 7, F–G 1, E–F 6) to find the best place for a site first-aid station: the place whose farthest other place is closest. Expected: E, with every place within 7 minutes.

Show a hint

Fill the matrix with both directions of every road, run the triple loop, then for each row take the maximum; pick the row with the smallest maximum.

Show the solution
Solution.cs
const int INF = int.MaxValue / 2;string names = "ABCDEFG";int n = names.Length;var d = new int[n, n];for (int i = 0; i < n; i++)    for (int j = 0; j < n; j++) d[i, j] = i == j ? 0 : INF; var roads = new[] { ("AB", 4), ("AD", 2), ("BE", 3), ("BC", 6), ("DE", 5), ("CE", 2), ("CF", 3), ("EG", 4), ("DG", 7), ("FG", 1), ("EF", 6) };foreach (var (r, w) in roads){    int a = names.IndexOf(r[0]), b = names.IndexOf(r[1]);    d[a, b] = d[b, a] = w;} for (int k = 0; k < n; k++)    for (int i = 0; i < n; i++)        for (int j = 0; j < n; j++)            if (d[i, k] + d[k, j] < d[i, j]) d[i, j] = d[i, k] + d[k, j]; int bestPlace = 0, bestWorst = INF;for (int i = 0; i < n; i++){    int worst = 0;    for (int j = 0; j < n; j++) worst = Math.Max(worst, d[i, j]);    if (worst < bestWorst) { bestWorst = worst; bestPlace = i; }}Console.WriteLine($"{names[bestPlace]}: every place within {bestWorst} minutes");
Output
E: every place within 7 minutes

Remember

  • Bellman-Ford relaxes every edge V − 1 times: O(V · E), works with negative weights.
  • If an extra pass still improves something, there is a negative cycle.
  • Floyd-Warshall computes all pairs with three loops (k outermost): O(V³).
  • Pick the algorithm by question (one source / all pairs) and weights (unweighted / non-negative / negative).
0 of 50 lessons completed