Introduction
The Floyd-Warshall algorithm is a classic algorithm used to find the shortest paths between all pairs of vertices in a weighted graph. It’s especially useful for dense graphs and can handle both positive and negative edge weights (though not negative cycles).
Algorithm
- Initialization:
- Create a distance matrix
dist
wheredist[i][j]
is the initial weight of the edge from vertexi
to vertexj
, or infinity if no edge exists. Setdist[i][i] = 0
for all verticesi
.
- Create a distance matrix
- Dynamic Programming Update:
- For each intermediate vertex
k
, update the distance matrix to consider paths that pass through vertexk
. - For each pair of vertices
(i, j)
, compute if a shorter path exists by going throughk
:if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; }
- For each intermediate vertex
- Result:
- After processing all vertices,
dist[i][j]
will contain the shortest path distance from vertexi
to vertexj
.
- After processing all vertices,
Pseudocode
function floydWarshall(graph):
dist = matrix of size VxV, initially filled with graph weights (or infinity if no edge exists)
for each vertex v:
dist[v][v] = 0
for each intermediate vertex k:
for each source vertex i:
for each destination vertex j:
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist
Code
Java
public class FloydWarshall {
private static final int INF = Integer.MAX_VALUE; // A large value representing infinity
public static void floydWarshall(int[][] graph) {
int V = graph.length;
int[][] dist = new int[V][V];
// Initialize the distance matrix
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
dist[i][j] = graph[i][j];
}
}
// Update the distance matrix considering each vertex as an intermediate vertex
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
// Print the final distance matrix
printSolution(dist);
}
private static void printSolution(int[][] dist) {
int V = dist.length;
System.out.println("Shortest distances matrix:");
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][j] == INF) {
System.out.print("INF ");
} else {
System.out.print(dist[i][j] + " ");
}
}
System.out.println();
}
}
}
Complexity
- ⏰ Time complexity:
O(V^3)
, whereV
is the number of vertices in the graph. This is due to the three nested loops each runningV
times. - 🧺 Space complexity:
O(V^2)
for storing the distance matrix.
Proof of Correctness
- The algorithm starts by correctly initializing the distance matrix with direct edge weights and zero for self-loops.
- It iteratively updates the shortest paths between all pairs of vertices by using each vertex as an intermediate point.
- In each iteration, the algorithm ensures that any path from
i
toj
through vertexk
is considered and the minimum distance is updated with the rule:dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
.
- By induction, after processing all vertices,
dist[i][j]
will correctly contain the shortest path distance between every pair of verticesi
andj
. - The Floyd-Warshall algorithm is thus guaranteed to provide the correct shortest paths for all pairs of vertices in the graph.
Transitive Closure
The transitive closure of a graph is a way to determine if there is a path between any two vertices. It indicates whether you can get from vertex i
to vertex j
through some sequence of edges.
Floyd-Warshall for Transitive Closure:
- Use the Floyd-Warshall algorithm to compute the transitive closure by modifying the distance matrix to a reachability matrix.
- Initialize the reachability matrix
reach[i][j]
to1
if there is a direct edge between verticesi
andj
, otherwise0
. Setreach[i][i]
to1
by definition.
and the update rules are:
- Use the standard Floyd-Warshall update rule to determine reachability:
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j])
- For each pair of vertices (
i
,j
), check if there is an indirect path through another vertexk
.
Final Reachability:
- After processing all vertices,
reach[i][j]
will be1
if there is some path (direct or indirect) fromi
toj
, otherwise0
.
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
}
}
}
So, in conclusion, this modified Floyd-Warshall algorithm can effectively compute the transitive closure, indicating the reachability between all pairs of vertices in the graph.