Kosaraju’s Algorithm is an algorithm that finds the strongly connected components of a directed graph in and space.
Tip
This problem can also be solved by Tarjan’s Strongly Connected Components Algorithm in time and space.
Algorithm
- Find an arbitrary depth-first search forest of . Let denote the exit time of during the depth-first search, and let be the vertices in the decreasing order of .
Lemma
Let
Then, let denote the set of the strongly connected components of , and let be the strongly connected components of in the decreasing order of , then is also a topological sort of the strongly connected components by their reachability.
Proof
It is easy to prove that
Lemma
Proof
Applying the definition yields .
Therefore,
Since is a topological sort by reachability, it follows that
- Apply the lemma to find .
- Find the strongly connected components of recursively.
Lemma
Proof
Since is a topological sort by reachability, it follows that
Since
it follows that, for any path from to in ,
Therefore,
- Applying the lemma yields that are the strongly connected components of .
This algorithm solves the problem in time and space.
std::vector<std::vector<int>> kosaraju(int n, int m, const std::vector<int> &u, const std::vector<int> &v) {
std::vector<std::vector<int>> adj(n), adjt(n);
for (int i = 0; i < m; i++) {
adj[u[i]].push_back(v[i]);
adjt[v[i]].push_back(u[i]);
}
std::vector vis(n, false);
std::vector<int> o;
for (int i = 0; i < n; i++) {
if (vis[i]) {
continue;
}
y_combinator([&](auto &&self, int u) -> void {
vis[u] = true;
for (int v : adj[u]) {
if (!vis[v]) {
self(v);
}
}
o.push_back(u);
})(i);
}
std::vector<std::vector<int>> res;
vis.assign(n, false);
for (int i : o | std::views::reverse) {
if (vis[i]) {
continue;
}
res.emplace_back();
y_combinator([&](auto &&self, int u) -> void {
res.back().push_back(u);
vis[u] = true;
for (int v : adjt[u]) {
if (!vis[v]) {
self(v);
}
}
})(i);
}
return res;
}