import java.util.*; import java.util.stream.Stream; // https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm public class SCCKosaraju { public static List> scc(List[] graph) { int n = graph.length; boolean[] used = new boolean[n]; List order = new ArrayList<>(); for (int i = 0; i < n; i++) if (!used[i]) dfs(graph, used, order, i); List[] reverseGraph = Stream.generate(ArrayList::new).limit(n).toArray(List[]::new); for (int i = 0; i < n; i++) for (int j : graph[i]) reverseGraph[j].add(i); List> components = new ArrayList<>(); Arrays.fill(used, false); Collections.reverse(order); for (int u : order) if (!used[u]) { List component = new ArrayList<>(); dfs(reverseGraph, used, component, u); components.add(component); } return components; } static void dfs(List[] graph, boolean[] used, List res, int u) { used[u] = true; for (int v : graph[u]) if (!used[v]) dfs(graph, used, res, v); res.add(u); } // DAG of strongly connected components public static List[] sccGraph(List[] graph, List> components) { int[] comp = new int[graph.length]; for (int i = 0; i < components.size(); i++) for (int u : components.get(i)) comp[u] = i; List[] g = Stream.generate(ArrayList::new).limit(components.size()).toArray(List[]::new); Set edges = new HashSet<>(); for (int u = 0; u < graph.length; u++) for (int v : graph[u]) if (comp[u] != comp[v] && edges.add(((long) comp[u] << 32) + comp[v])) g[comp[u]].add(comp[v]); return g; } // Usage example public static void main(String[] args) { List[] g = Stream.generate(ArrayList::new).limit(3).toArray(List[]::new); g[2].add(0); g[2].add(1); g[0].add(1); g[1].add(0); List> components = scc(g); System.out.println(components); System.out.println(Arrays.toString(sccGraph(g, components))); } }