Graph · 22 of 43
Implement Floyd Warshall Algorithm
Fill a price table for every pair of towns by letting each town, one at a time, act as a stop in the middle.
- Simple way
- time O(V^2 * E)
room O(V^2) - Clever way
- time O(V^3)
room O(V^2)
The problem, simply
You get V towns and one-way roads with prices. Some prices may be negative, but there is no loop whose prices add up to less than zero.
Fill a table where cell [i][j] is the cheapest price to get from town i to town j, for every pair of towns at once. If there is no way, the cell says infinity.
A story to remember it
Picture it
Four towns and seven one-way roads. Roads between 0 and 1 and between 0 and 3 go both ways with different prices, so they are drawn as two curved arrows.
Examples
The picture above
- In
V = 4, edges = [[0,1,3],[0,3,7],[1,0,8],[1,2,2],[2,0,5],[2,3,1],[3,0,2]]- Out
[[0,3,5,6],[5,0,2,3],[3,6,0,1],[2,5,7,0]]
From 1 to 0 the direct road costs 8, but 1, 2, 3, 0 costs 2 + 1 + 2 = 5.
A negative road
- In
V = 3, edges = [[0,1,4],[1,2,-2],[0,2,3]]- Out
[[0,4,2],[INF,0,-2],[INF,INF,0]]
Going 0, 1, 2 costs 4 - 2 = 2, which beats the direct road of 3. Nothing leads back to 0, so those cells stay INF.
A loop that pays you
- In
V = 2, edges = [[0,1,1],[1,0,-2]]- Out
negative cycle
After the table is filled, cell [0][0] is 1 - 2 = -1. A town that is cheaper than free to reach from itself means a negative loop.
One town
- In
V = 1, edges = []- Out
[[0]]
Getting from a town to itself costs nothing.
Way 1: the simple way
Run a single-start shortest path method from every town. Because roads can be negative, use Bellman Ford: from each start, relax every road V - 1 times.
- For each start
s, setdist[s][s] = 0and the rest to infinity. - Repeat
V - 1times: for every roadu > vwith pricew, trydist[s][u] + wfordist[s][v].
import java.util.*;
class Solution {
static final int INF = 1_000_000_000;
public int[][] allPairs(int V, int[][] edges) {
int[][] dist = new int[V][V];
for (int s = 0; s < V; s++) {
Arrays.fill(dist[s], INF);
dist[s][s] = 0;
for (int round = 1; round < V; round++) { // Bellman Ford from s
for (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
if (dist[s][u] != INF && dist[s][u] + w < dist[s][v]) {
dist[s][v] = dist[s][u] + w;
}
}
}
}
return dist;
}
}How long it takes: V starts, each doing V - 1 rounds over E roads, O(V^2 * E). In a busy map E is close to V^2, so that is O(V^4). Extra room: the table, O(V^2). If no road is negative, running Dijkstra from every town is faster, O(V * E log V).
Way 2: the clever way
Let the towns take turns being the changing town. When town k gets its turn, every cell asks one question:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
The left half of the trip, i to k, sits in column k of row i. The right half, k to j, sits in row k. Both halves already use only the changing towns before k, so after town k's turn, every cell knows the cheapest trip that changes only at towns 0 to k.
- Copy the direct prices into the table. Put 0 on the diagonal and infinity where there is no road.
- For
kfrom0toV - 1, for everyi, for everyj: try going throughk. - Afterwards, any negative number on the diagonal means a negative loop.
Each town takes a turn as the middle stop
01 / 17
Start with the table of direct roads. A cell says how much it costs to go from its row town to its column town with no towns in between. inf means there is no direct road.
- looking now
- checking
- done
- answer
- just added
import java.util.*;
class Solution {
static final int INF = 1_000_000_000;
// returns null when there is a negative loop
public int[][] floydWarshall(int V, int[][] edges) {
int[][] dist = new int[V][V];
for (int i = 0; i < V; i++) {
Arrays.fill(dist[i], INF);
dist[i][i] = 0;
}
for (int[] e : edges) dist[e[0]][e[1]] = Math.min(dist[e[0]][e[1]], e[2]);
for (int k = 0; k < V; k++) { // k must be the outer loop
for (int i = 0; i < V; i++) {
if (dist[i][k] == INF) continue; // no way to reach k from i
for (int j = 0; j < V; j++) {
if (dist[k][j] == INF) continue;
if (dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
for (int i = 0; i < V; i++) if (dist[i][i] < 0) return null; // negative loop
return dist;
}
}How long it takes: three loops of V each, O(V^3). Extra room: the table, O(V^2). It updates the table in place; row k and column k do not change during turn k, so reading and writing the same table is safe.
Watch out for
- Using
Integer.MAX_VALUEfor infinity. Adding two of them overflows. Use a big number like1_000_000_000and skip cells that are infinity. - Two roads between the same towns. Keep the cheaper one when you fill the table.
- Forgetting the 0 on the diagonal. Without it, the trip from a town to itself looks impossible.
- GeeksforGeeks gives a matrix with
-1for no road. Turn-1into infinity first, then back into-1at the end.
What interviewers ask next
- How do you print the actual route? Keep
next[i][j], the first town afteri. When going throughkwins, setnext[i][j] = next[i][k], then follownextfromitoj. - Which pairs can reach each other at all? Use the same three loops with true and false:
reach[i][j] |= reach[i][k] && reach[k][j]. That is the transitive closure. - Floyd Warshall or Dijkstra from every town? With few roads and no negative prices, Dijkstra from every town,
O(V * E log V), wins. With many roads or negative prices, the simpleO(V^3)loops are hard to beat. - Find the city with the fewest neighbours within a distance limit (LeetCode 1334)? Fill the table with Floyd Warshall, then count each row.
- Why is it dynamic programming? Each turn reuses the answers of the previous turn: the best trip using middle towns up to
kis built from best trips using towns up tok - 1.
Remember this
Grown-up words: towns are vertices, roads are directed weighted edges, the price table is the distance matrix, the changing town is the intermediate vertex, and filling the table this way is the Floyd Warshall algorithm, an all pairs shortest path method built on dynamic programming.