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

  1. 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.

Lemma

  1. Apply the lemma to find .
  2. Find the strongly connected components of recursively.

Lemma

  1. 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;
}