Jump to content

Kosaraju

From Rosetta Code
Task
Kosaraju
You are encouraged to solve this task according to the task description, using any language you may know.
This page uses content from Wikipedia. The original article was at Graph. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)


Kosaraju's algorithm (also known as the Kosaraju–Sharir algorithm) is a linear time algorithm to find the strongly connected components of a directed graph. Aho, Hopcroft and Ullman credit it to an unpublished paper from 1978 by S. Rao Kosaraju. The same algorithm was independently discovered by Micha Sharir and published by him in 1981. It makes use of the fact that the transpose graph (the same graph with the direction of every edge reversed) has exactly the same strongly connected components as the original graph.
For this task consider the directed graph with these connections:

 0 -> 1
 1 -> 2
 2 -> 0
 3 -> 1,  3 -> 2,  3 -> 4
 4 -> 3,  4 -> 5
 5 -> 2,  5 -> 6
 6 -> 5
 7 -> 4, 7  -> 6, 7 -> 7

And report the kosaraju strongly connected component for each node.

References

11l

Translation of: Python
F kosaraju(g)
   V size = g.len
   V vis = [0B] * size
   V l = [0] * size
   V x = size
   V t = [[Int]()] * size

   F visit(Int u) -> Void
      I !@vis[u]
         @vis[u] = 1B
         L(v) @g[u]
            @visit(v)
            @t[v] [+]= u
         @x--
         @l[@x] = u

   L(u) 0 .< g.len
      visit(u)
   V c = [0] * size

   F assign(Int u, root) -> Void
      I @vis[u]
         @vis[u] = 0B
         @c[u] = root
         L(v) @t[u]
            @assign(v, root)

   L(u) l
      assign(u, u)
   R c

V g = [[1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7]]
print(kosaraju(g))
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

C#

using System;
using System.Collections.Generic;

class Node
{
	public enum Colors
	{
		Black, White, Gray
	}

	public Colors color { get; set; }
	public int N { get; }
	
	public Node(int n)
	{
		N = n;
		color = Colors.White;
	}
}

class Graph
{
	public HashSet<Node> V { get; }
	public Dictionary<Node, HashSet<Node>> Adj { get; }

	/// <summary>
	/// Kosaraju's strongly connected components algorithm
	/// </summary>
	public void Kosaraju()
	{
		var L = new HashSet<Node>();

		Action<Node> Visit = null;
		Visit = (u) =>
		{
			if (u.color == Node.Colors.White)
			{
				u.color = Node.Colors.Gray;

				foreach (var v in Adj[u])
					Visit(v);

				L.Add(u);
			}
		};

		Action<Node, Node> Assign = null;
		Assign = (u, root) =>
		{
			if (u.color != Node.Colors.Black)
			{
				if (u == root)
					Console.Write("SCC: ");

				Console.Write(u.N + " ");
				u.color = Node.Colors.Black;

				foreach (var v in Adj[u])
					Assign(v, root);

				if (u == root)
					Console.WriteLine();
			}
		};

		foreach (var u in V)
			Visit(u);

		foreach (var u in L)
			Assign(u, u);
	}
}

C++

Translation of: D
#include <functional>
#include <iostream>
#include <ostream>
#include <vector>

template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
    auto it = v.cbegin();
    auto end = v.cend();

    os << "[";
    if (it != end) {
        os << *it;
        it = std::next(it);
    }
    while (it != end) {
        os << ", " << *it;
        it = std::next(it);
    }
    return os << "]";
}

std::vector<int> kosaraju(std::vector<std::vector<int>>& g) {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    auto size = g.size();
    std::vector<bool> vis(size);           // all false by default
    std::vector<int> l(size);              // all zero by default
    auto x = size;                         // index for filling l in reverse order
    std::vector<std::vector<int>> t(size); // transpose graph

    // Recursive subroutine 'visit':
    std::function<void(int)> visit;
    visit = [&](int u) {
        if (!vis[u]) {
            vis[u] = true;
            for (auto v : g[u]) {
                visit(v);
                t[v].push_back(u); // construct transpose
            }
            l[--x] = u;
        }
    };

    // 2. For each vertex u of the graph do visit(u)
    for (int i = 0; i < g.size(); ++i) {
        visit(i);
    }
    std::vector<int> c(size); // used for component assignment

    // Recursive subroutine 'assign':
    std::function<void(int, int)> assign;
    assign = [&](int u, int root) {
        if (vis[u]) { // repurpose vis to mean 'unassigned'
            vis[u] = false;
            c[u] = root;
            for (auto v : t[u]) {
                assign(v, root);
            }
        }
    };

    // 3: For each element u of l in order, do assign(u, u)
    for (auto u : l) {
        assign(u, u);
    }

    return c;
}

std::vector<std::vector<int>> g = {
    {1},
    {2},
    {0},
    {1, 2, 4},
    {3, 5},
    {2, 6},
    {5},
    {4, 6, 7},
};

int main() {
    using namespace std;

    cout << kosaraju(g) << endl;

    return 0;
}
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

D

Translation of: Kotlin

(mostly) with output like

Translation of: Go
import std.container.array;
import std.stdio;

/* the list index is the first vertex in the edge(s) */
auto g = [
    [1],
    [2],
    [0],
    [1, 2, 4],
    [3, 5],
    [2, 6],
    [5],
    [4, 6, 7],
];

int[] kosaraju(int[][] g) {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    auto size = g.length; // all false by default
    Array!bool vis;
    vis.length = size;
    int[] l;              // all zero by default
    l.length = size;
    auto x = size;        // index for filling l in reverse order
    int[][] t;            // transpose graph
    t.length = size;

    // Recursive subroutine 'visit':
    void visit(int u) {
        if (!vis[u]) {
            vis[u] = true;
            foreach (v; g[u]) {
                visit(v);
                t[v] ~= u;  // construct transpose
            }
            l[--x] = u;
        }
     }

    // 2. For each vertex u of the graph do visit(u)
    foreach (u, _; g) {
        visit(u);
    }
    int[] c;  // used for component assignment
    c.length = size;

    // Recursive subroutine 'assign':
    void assign(int u, int root) {
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false;
            c[u] = root;
            foreach(v; t[u]) {
                assign(v, root);
            }
        }
    }

    // 3: For each element u of l in order, do assign(u, u)
    foreach (u; l) {
        assign(u, u);
    }

    return c;
}

void main() {
    writeln(kosaraju(g));
}
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Delphi

Translation of: Go
program KosarajuApp;

uses
  System.SysUtils;

type
  TKosaraju = TArray<TArray<Integer>>;

var
  g: TKosaraju;

procedure Init();
begin
  SetLength(g, 8);
  g[0] := [1];
  g[1] := [2];
  g[2] := [0];
  g[3] := [1, 2, 4];
  g[4] := [3, 5];
  g[5] := [2, 6];
  g[6] := [5];
  g[7] := [4, 6, 7];
end;

procedure Println(vector: TArray<Integer>);
var
  i: Integer;
begin
  write('[');
  if (Length(vector) > 0) then
    for i := 0 to High(vector) do
    begin
      write(vector[i]);
      if (i < high(vector)) then
        write(', ');
    end;

  writeln(']');
end;

function Kosaraju(g: TKosaraju): TArray<Integer>;
var
  vis: TArray<Boolean>;
  L, c: TArray<Integer>;
  x: Integer;
  t: TArray<TArray<Integer>>;
  Visit: TProc<Integer>;
  u: Integer;
  Assign: TProc<Integer, Integer>;
begin
  // 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
  SetLength(vis, Length(g));
  SetLength(L, Length(g));
  x := Length(L);
  // index for filling L in reverse order
  SetLength(t, Length(g)); // transpose graph

  // 2. recursive subroutine:

  Visit := procedure(u: Integer)
    begin
      if (not vis[u]) then
      begin
        vis[u] := true;
        for var v in g[u] do
        begin
          Visit(v);
          t[v] := concat(t[v], [u]);
          // construct transpose
        end;

        dec(x);
        L[x] := u;
      end;
    end;

  // 2. For each vertex u of the graph do Visit(u)

  for u := 0 to High(g) do
  begin
    Visit(u);
  end;

  SetLength(c, Length(g)); // result, the component assignment

  // 3: recursive subroutine:

  Assign := procedure(u, root: Integer)
    begin
      if vis[u] then
      // repurpose vis to mean "unassigned"
      begin
        vis[u] := false;
        c[u] := root;

        for var v in t[u] do
          Assign(v, root);
      end;
    end;

  // 3: For each element u of L in order, do Assign(u,u)

  for u in L do
    Assign(u, u);

  Result := c;
end;

begin
  Init;
  Println(Kosaraju(g));
end.
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

EasyLang

Translation of: Kotlin
sysconf zero_based
# 
g[][] = [ [ 1 ] [ 2 ] [ 0 ] [ 1 2 4 ] [ 3 5 ] [ 2 6 ] [ 5 ] [ 4 6 7 ] ]
gc = len g[][]
len vis[] gc
len l[] gc
x = gc
len t[][] gc
proc visit u . .
   if vis[u] = 0
      vis[u] = 1
      for v in g[u][]
         visit v
         t[v][] &= u
      .
      x -= 1
      l[x] = u
   .
.
for i range0 gc
   visit i
.
len c[] gc
proc assign u root . .
   if vis[u] = 1
      vis[u] = 0
      c[u] = root
      for v in t[u][]
         assign v root
      .
   .
.
for u in l[]
   assign u u
.
print c[]
Output:
[ 0 0 0 3 3 5 5 7 ]

FreeBASIC

Translation of: Go
' Define a custom type for a dynamic array of integers
Type IntArray
    Dato As Integer Ptr
    Size As Integer
End Type

' Function to add an element to the IntArray
Sub AddToIntArray(arr As IntArray Ptr, value As Integer)
    arr->Size += 1
    arr->Dato = Reallocate(arr->Dato, arr->Size * Sizeof(Integer))
    arr->Dato[arr->Size - 1] = value
End Sub

' Define the graph as an array of IntArrays
Dim Shared As IntArray g(7)
' Global variables for Kosaraju's algorithm
Dim Shared As IntArray t(7)
Dim Shared As Boolean vis(7)
Dim Shared As Integer x, L(7), c(7)

' Initialize the graph 
Sub InitGraph()
    Dim As Integer i, j
    Dim As Integer edges(7, 3) = {{1},{2},{0},{1,2,4},{3,5},{2,6},{5},{4,6,7}}
    For i = 0 To 7
        For j = 0 To 2
            If edges(i, j) >= 0 Then AddToIntArray(@g(i), edges(i, j))
        Next
    Next
End Sub

Sub Visit(u As Integer)
    If Not vis(u) Then
        vis(u) = True
        For i As Integer = 0 To g(u).Size - 1
            Visit(g(u).Dato[i])
            AddToIntArray(@t(g(u).Dato[i]), u)
        Next
        x -= 1
        L(x) = u
    End If
End Sub

Sub Assign(u As Integer, root As Integer)
    If vis(u) Then
        vis(u) = False
        c(u) = root
        For i As Integer = 0 To t(u).Size - 1
            Assign(t(u).Dato[i], root)
        Next
    End If
End Sub

Sub Kosaraju(n As Integer)
    Dim As Integer i
    ' Initialize variables
    For i = 0 To n-1
        vis(i) = False
        t(i).Size = 0
        If t(i).Dato Then Deallocate(t(i).Dato)
    Next
    x = n
    
    ' Visit all vertices
    For i = 0 To n-1
        Visit(i)
    Next
    
    ' Reset visited array
    For i = 0 To n-1
        vis(i) = True
    Next
    
    ' Free temporary arrays
    For i = 0 To n-1
        Assign(L(i), L(i))
    Next
End Sub

InitGraph()
Dim n As Integer = 8 ' Number of vertices
Kosaraju(n)

For i As Integer = 0 To n-1
    ' Print the result
    Print c(i);
    ' Free allocated memory
    If g(i).Dato Then Deallocate(g(i).Dato)
    If t(i).Dato Then Deallocate(t(i).Dato)
Next

Sleep
Output:
 0 0 0 3 3 5 5 7

Go

package main

import "fmt"

var g = [][]int{
    0: {1},
    1: {2},
    2: {0},
    3: {1, 2, 4},
    4: {3, 5},
    5: {2, 6},
    6: {5},
    7: {4, 6, 7},
}

func main() {
    fmt.Println(kosaraju(g))
}

func kosaraju(g [][]int) []int {
    // 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    vis := make([]bool, len(g))
    L := make([]int, len(g))
    x := len(L)                // index for filling L in reverse order
    t := make([][]int, len(g)) // transpose graph
    // 2. recursive subroutine:
    var Visit func(int)
    Visit = func(u int) {
        if !vis[u] {
            vis[u] = true
            for _, v := range g[u] {
                Visit(v)
                t[v] = append(t[v], u) // construct transpose
            }
            x--
            L[x] = u
        }
    }
    // 2. For each vertex u of the graph do Visit(u)
    for u := range g {
        Visit(u)
    }
    c := make([]int, len(g)) // result, the component assignment
    // 3: recursive subroutine:
    var Assign func(int, int)
    Assign = func(u, root int) {
        if vis[u] { // repurpose vis to mean "unassigned"
            vis[u] = false
            c[u] = root
            for _, v := range t[u] {
                Assign(v, root)
            }
        }
    }
    // 3: For each element u of L in order, do Assign(u,u)
    for _, u := range L {
        Assign(u, u)
    }
    return c
}
Output:
[0 0 0 3 3 5 5 7]

J

Implementation:

kosaraju=: {{
  coerase([cocurrent)cocreate''
  visit=: {{
    if.y{unvisited do.
      unvisited=: 0 y} unvisited
      visit y{::out
      L=: y,L
    end.
  }}"0
  assign=: {{
    if._1=y{assigned do.
      assigned=: x y} assigned
      x&assign y{::in
    end.
  }}"0
  out=: y
  in=: <@I.|:y e.S:0~i.#y
  unvisited=: 1#~#y
  assigned=: _1#~#y
  L=: i.0
  visit"0 i.#y
  assign~L
  assigned
}}

Task example (tree representation: each value here is the index of the parent node):

   kosaraju 1;2;0;1 2 4;3 5;2 6;5;4 6 7
0 0 0 3 3 5 5 7

Alternatively, we could represent the result as a graph of the same type as our argument graph. The implementation of visit remains the same:

kosarajud=: {{
  coerase([cocurrent)cocreate''
  visit=: {{
    if.y{unvisited do.
      unvisited=: 0 y} unvisited
      visit y{::out
      L=: y,L
    end.
  }}"0
  assign=: {{
    if.-.y e.;assigned do.
      assigned=: (y,L:0~x{assigned) x} assigned
      x&assign y{::in
    end.
  }}"0
  out=: y
  in=: <@I.|:y e.S:0~i.#y
  unvisited=: 1#~#y
  assigned=: a:#~#y
  L=: i.0
  visit"0 i.#y
  assign~L
  assigned
}}

   kosarajud 1;2;0;1 2 4;3 5;2 6;5;4 6 7
┌─────┬┬┬───┬┬───┬┬─┐
0 2 1│││3 4││5 6││7
└─────┴┴┴───┴┴───┴┴─┘

But it would probably be simpler to convert the result from the tree representation to our directed graph representation:

   ((<@I.@e."1 0)i.@#) 0 0 0 3 3 5 5 7
┌─────┬┬┬───┬┬───┬┬─┐
0 1 2│││3 4││5 6││7
└─────┴┴┴───┴┴───┴┴─┘

Java

Translation of: Kotlin

Output is like Go instead of what Kotlin outputs.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.IntConsumer;
import java.util.stream.Collectors;

public class Kosaraju {
    static class Recursive<I> {
        I func;
    }

    private static List<Integer> kosaraju(List<List<Integer>> g) {
        // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
        int size = g.size();
        boolean[] vis = new boolean[size];
        int[] l = new int[size];
        AtomicInteger x = new AtomicInteger(size);

        List<List<Integer>> t = new ArrayList<>();
        for (int i = 0; i < size; ++i) {
            t.add(new ArrayList<>());
        }

        Recursive<IntConsumer> visit = new Recursive<>();
        visit.func = (int u) -> {
            if (!vis[u]) {
                vis[u] = true;
                for (Integer v : g.get(u)) {
                    visit.func.accept(v);
                    t.get(v).add(u);
                }
                int xval = x.decrementAndGet();
                l[xval] = u;
            }
        };

        // 2. For each vertex u of the graph do visit(u)
        for (int i = 0; i < size; ++i) {
            visit.func.accept(i);
        }
        int[] c = new int[size];

        Recursive<BiConsumer<Integer, Integer>> assign = new Recursive<>();
        assign.func = (Integer u, Integer root) -> {
            if (vis[u]) {  // repurpose vis to mean 'unassigned'
                vis[u] = false;
                c[u] = root;
                for (Integer v : t.get(u)) {
                    assign.func.accept(v, root);
                }
            }
        };

        // 3: For each element u of l in order, do assign(u, u)
        for (int u : l) {
            assign.func.accept(u, u);
        }

        return Arrays.stream(c).boxed().collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<List<Integer>> g = new ArrayList<>();
        for (int i = 0; i < 8; ++i) {
            g.add(new ArrayList<>());
        }
        g.get(0).add(1);
        g.get(1).add(2);
        g.get(2).add(0);
        g.get(3).add(1);
        g.get(3).add(2);
        g.get(3).add(4);
        g.get(4).add(3);
        g.get(4).add(5);
        g.get(5).add(2);
        g.get(5).add(6);
        g.get(6).add(5);
        g.get(7).add(4);
        g.get(7).add(6);
        g.get(7).add(7);

        List<Integer> output = kosaraju(g);
        System.out.println(output);
    }
}
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

jq

Translation of: Go
# Fill an array of the specified length with the input value
def dimension($n): . as $in | [range(0;$n) | $in];

# $graph should be an adjacency-list graph with IO==0
def korasaju($graph): 
  ($graph|length) as $length
  | def init: { 
        vis: (false | dimension($length)),  # visited
        L: [],                              # for an array of $length integers
        t: ([]|dimension($length)),         # transposed graph
        x: $length                          # index       
      };

    # input: {vis, L, t, x, t}
    def visit($u):
      if .vis[$u] | not
      then .vis[$u] = true
      |  reduce ($graph[$u][]) as $v (.;
              visit($v)
              | .t[$v] += [$u] )
      | .x -= 1
      | .L[.x] = $u
      else .
      end ;

    # input: {vis, t, c}
    def assign($u; $root):
      if .vis[$u]
      then .vis[$u] = false
      | .c[$u] = $root
      | reduce .t[$u][] as $v (.; assign($v; $root))
      else .
      end ;

    # For each vertex u of the graph, mark u as unvisited.
    init

    # For each vertex u of the graph do visit(u)
    | reduce range(0;$length) as $u (.; visit($u))
    | .c = (null|dimension($length))

    # For each element u of L in order, do assign(u, u)
    | reduce .L[] as $u (.; assign($u; $u) )
    | .c ;

# An example adjacency list using IO==1
def g: [
    [1],
    [2],
    [0],
    [1, 2, 4],
    [3, 5],
    [2, 6],
    [5],
    [4, 6, 7]
];

korasaju(g)
Output:

With the jq program above in korasaju.jq, the invocation `jq -nc -f korasaju.jq` produces:

[0,0,0,3,3,5,5,7]

Julia

Works with: Julia version 0.6
Translation of: Go
function korasaju(g::Vector{Vector{T}}) where T<:Integer
    # 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    vis = falses(length(g))
    L   = Vector{T}(length(g))
    x   = length(L) + 1
    t   = collect(T[] for _ in eachindex(g))

    # Recursive
    function visit(u::T)
        if !vis[u]
            vis[u] = true
            for v in g[u]
                visit(v)
                push!(t[v], u)
            end
            x -= 1
            L[x] = u
        end
    end
    # 2. For each vertex u of the graph do visit(u)
    for u in eachindex(g)
        visit(u)
    end
    c = Vector{T}(length(g))
    # 3. Recursive subroutine:
    function assign(u::T, root::T)
        if vis[u]
            vis[u] = false
            c[u] = root
            for v in t[u]
                assign(v, root)
            end
        end
    end
    # 3. For each element u of L in order, do assign(u, u)
    for u in L
        assign(u, u)
    end
    return c
end

g = [[2], [3], [1], [2, 3, 5], [4, 6], [3, 7], [6], [5, 7, 8]]
println(korasaju(g))
Output:
[1, 1, 1, 4, 4, 6, 6, 8]

K

Works with: ngn/k
F:{[g]     / graph
 n: #g     / number of vertices
 v::&n     / visited?
 L::!0     / dfs order
 V: {[g;x] $[v x;;[v[x]:1;o[g]'g x;L::x,L]];}[g]
 V'!n      / Visit
 G: @[n#,!0;g;,;!n] / transposed graph
 c::n#-1   / assigned components
 A: {[G;x;y] $[-1=c x;[c[x]:y;G[x]o[G]'y];]}[G]'
 A'/2#,L   / Assign
 .=c}
  F(1;2;0;1 2 4;3 5;2 6;5;4 6 7)
(0 1 2
 3 4
 5 6
 ,7)

Alternative implementation, without global assignments:

F:{[g]             /graph
 n:#g              /number of vertices
 G:@[n#,!0;g;,;!n] /transposed graph
 V:{[g;L;x]$[^L?x;(1_(x,L)o[g]/g x),x;L]}[g]
 L:|V/[!0;!#g]     /Visit
 A:{[G;c;u;r]$[0>c u;o[G]/[@[c;u;:;r];G u;r];c]}[G]
 .=A/[n#-1;L;L]}   /Assign

(result is the same)

Works with: Kona
F:{[g]     / graph
 n: #g     / number of vertices
 v::&n     / visited?
 L::!0     / dfs order
 V: {[g;x] :[v x;;[v[x]:1;_f[g]'g x;L::x,L]];}[g]
 V'!n      / Visit
 G: @[n#,!0;g;,;!n] / transposed graph
 c::n#-1   / assigned components
 A: {[G;x;y] :[-1=c x;[c[x]:y;G[x]_f[G]'y];]}[G]'
 A'/2#,L   / Assign
 .=c}

(result is the same)

Kotlin

Translation of: Go
// version 1.1.3

/* the list index is the first vertex in the edge(s) */
val g = listOf(
    intArrayOf(1),        // 0
    intArrayOf(2),        // 1
    intArrayOf(0),        // 2
    intArrayOf(1, 2, 4),  // 3
    intArrayOf(3, 5),     // 4
    intArrayOf(2, 6),     // 5
    intArrayOf(5),        // 6
    intArrayOf(4, 6, 7)   // 7
)
    
fun kosaraju(g: List<IntArray>): List<List<Int>> {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    val size = g.size
    val vis = BooleanArray(size)                 // all false by default
    val l = IntArray(size)                       // all zero by default
    var x = size                                 // index for filling l in reverse order
    val t = List(size) { mutableListOf<Int>() }  // transpose graph
    
    // Recursive subroutine 'visit':
    fun visit(u: Int) {
        if (!vis[u]) {
            vis[u] = true
            for (v in g[u]) { 
                visit(v)
                t[v].add(u)  // construct transpose 
            }
            l[--x] = u
        }
     }

    // 2. For each vertex u of the graph do visit(u)
    for (u in g.indices) visit(u)
    val c = IntArray(size)  // used for component assignment 

    // Recursive subroutine 'assign':
    fun assign(u: Int, root: Int) {
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for (v in t[u]) assign(v, root)
        }
    }

    // 3: For each element u of l in order, do assign(u, u)
    for (u in l) assign(u, u)

    // Obtain list of SCC's from 'c' and return it   
    return c.withIndex()
            .groupBy { it.value }.values
            .map { ivl -> ivl.map { it.index } }
}

fun main(args: Array<String>) {
    println(kosaraju(g).joinToString("\n"))
}
Output:
[0, 1, 2]
[3, 4]
[5, 6]
[7]

Lua

Translation of: C++
function write_array(a)
    io.write("[")
    for i=0,#a do
        if i>0 then
            io.write(", ")
        end
        io.write(tostring(a[i]))
    end
    io.write("]")
end

function kosaraju(g)
    -- 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    local size = #g

    local vis = {}
    for i=0,size do
        -- all false by default
        vis[i] = false
    end

    local l = {}
    for i=0,size do
        -- all zero by default
        l[i] = 0
    end

    local x = size+1  -- index for filling l in reverse order

    local t = {}    -- transpose graph

    -- Recursive subroutine 'visit'
    function visit(u)
        if not vis[u] then
            vis[u] = true
            for i=0,#g[u] do
                local v = g[u][i]
                visit(v)
                if t[v] then
                    local a = t[v]
                    a[#a+1] = u
                else
                    t[v] = {[0]=u}
                end
            end
            x = x - 1
            l[x] = u
        end
    end

    -- 2. For each vertex u of the graph do visit(u)
    for i=0,#g do
        visit(i)
    end
    local c = {}
    for i=0,size do
        -- used for component assignment
        c[i] = 0
    end

    -- Recursive subroutine 'assign'
    function assign(u, root)
        if vis[u] then  -- repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for i=0,#t[u] do
                local v = t[u][i]
                assign(v, root)
            end
        end
    end

    -- 3: For each element u of l in order, do assign(u, u)
    for i=0,#l do
        local u = l[i]
        assign(u, u)
    end

    return c
end

-- main
local g = {
    [0]={[0]=1},
    [1]={[0]=2},
    [2]={[0]=0},
    [3]={[0]=1, [1]=2, [2]=4},
    [4]={[0]=3, [1]=5},
    [5]={[0]=2, [1]=6},
    [6]={[0]=5},
    [7]={[0]=4, [1]=6, [2]=7},
}

write_array(kosaraju(g))
print()
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Mathematica /Wolfram Language

g = Graph[{0 -> 1, 1 -> 2, 2 -> 0, 3 -> 1, 3 -> 2, 3 -> 4, 4 -> 3, 
    4 -> 5, 5 -> 2, 5 -> 6, 6 -> 5, 7 -> 4, 7 -> 6, 7 -> 7}];
cc = ConnectedComponents[g]
Catenate[ConstantArray[Min[#], Length[#]] & /@ SortBy[cc, First]]
Output:
{{0, 1, 2}, {5, 6}, {3, 4}, {7}}
{0, 0, 0, 3, 3, 5, 5, 7}

Nim

Translation of: Kotlin
type
  Vertex = int
  Graph = seq[seq[Vertex]]
  Scc = seq[Vertex]

func korasaju(g: Graph): seq[Scc] =

  var
    size = g.len
    visited = newSeq[bool](size)        # All false by default.
    l = newSeq[Vertex](size)            # All zero by default.
    x = size                            # Index for filling "l" in reverse order.
    t = newSeq[seq[Vertex]](size)       # Transposed graph.
    c = newSeq[Vertex](size)            # Used for component assignment.

  func visit(u: Vertex) =
    if not visited[u]:
      visited[u] = true
      for v in g[u]:
        visit(v)
        t[v].add(u)   # Construct transposed graph.
      dec x
      l[x] = u

  func assign(u, root: Vertex) =
    if visited[u]:
      # Repurpose visited to mean 'unassigned'.
      visited[u] = false
      c[u] = root
      for v in t[u]: v.assign(root)

  for u in 0..g.high: u.visit()
  for u in l: u.assign(u)

  # Build list of strongly connected components.
  var prev = -1
  for v1, v2 in c:
    if v2 != prev:
      prev = v2
      result.add @[]
    result[^1].add v1


when isMainModule:
  let g = @[@[1], @[2], @[0], @[1, 2, 4], @[3, 5], @[2, 6], @[5], @[4, 6, 7]]
  for scc in korasaju(g): echo $scc
Output:
@[0, 1, 2]
@[3, 4]
@[5, 6]
@[7]

Pascal

Works with FPC (tested with version 3.2.2).

program Kosaraju_SCC;
{$mode objfpc}{$modeswitch arrayoperators}
{$j-}{$coperators on}
type
  TDigraph = array of array of Integer;

procedure PrintComponents(const g: TDigraph);
var
  Visited: array of Boolean = nil;
  RevPostOrder: array of Integer = nil;
  gr: TDigraph = nil; //reversed graph
  Counter, Next: Integer;
  FirstItem: Boolean;

  procedure Dfs1(aNode: Integer);
  begin
    Visited[aNode] := True;
    for Next in g[aNode] do begin
      gr[Next] += [aNode];
      if not Visited[Next] then
        Dfs1(Next);
    end;
    RevPostOrder[Counter] := aNode;
    Dec(Counter);
  end;

  procedure Dfs2(aNode: Integer);
  begin
    Visited[aNode] := True;
    for Next in gr[aNode] do
      if not Visited[Next] then
        Dfs2(Next);
    if FirstItem then begin
      FirstItem := False;
      Write(aNode);
    end else
      Write(', ', aNode);
  end;

var
  Node: Integer;
begin
  SetLength(Visited, Length(g));
  SetLength(RevPostOrder, Length(g));
  SetLength(gr, Length(g));
  Counter := High(g);
  for Node := 0 to High(g) do
    if not Visited[Node] then
      Dfs1(Node);
  FillChar(Pointer(Visited)^, Length(Visited), 0);
  for Node in RevPostOrder do
    if not Visited[Node] then begin
      FirstItem := True;
      Write('[');
      Dfs2(Node);
      WriteLn(']');
    end; 
end;

const
  g: TDigraph = (
    (1),
    (2),
    (0),
    (1, 2, 4),
    (3, 5),
    (2, 6),
    (5),
    (4, 6, 7)
  );
begin
  PrintComponents(g);
end.
Output:
[7]
[4, 3]
[6, 5]
[1, 2, 0]

Perl

Translation of: Raku
use strict;
use warnings;
use feature 'say';

sub kosaraju {
    our(%k) = @_;
    our %g = ();
    our %h;
    my $i = 0;
    $g{$_}     = $i++ for sort keys %k;
    $h{$g{$_}} = $_   for      keys %g; # invert

    our(%visited, @stack, @transpose, @connected);
    sub visit {
        my($u) = @_;
        unless ($visited{$u}) {
            $visited{$u} = 1;
            for my $v (@{$k{$u}}) {
                visit($v);
                push @{$transpose[$g{$v}]}, $u;
            }
            push @stack, $u;
        }
    }

    sub assign {
        my($u, $root) = @_;
        if ($visited{$u}) {
            $visited{$u} = 0;
            $connected[$g{$u}] = $root;
            assign($_, $root) for @{$transpose[$g{$u}]};
        }
    }

    visit($_) for sort keys %g;
    assign($_, $_) for reverse @stack;

    my %groups;
    for my $i (0..$#connected) {
        my $id = $g{$connected[$i]};
        push @{$groups{$id}}, $h{$i};
    }
    say join ' ', @{$groups{$_}} for sort keys %groups;
}

my %test1 = (
    0 => [1],
    1 => [2],
    2 => [0],
    3 => [1, 2, 4],
    4 => [3, 5],
    5 => [2, 6],
    6 => [5],
    7 => [4, 6, 7]
);

my %test2 = (
   'Andy' => ['Bart'],
   'Bart' => ['Carl'],
   'Carl' => ['Andy'],
   'Dave' => [<Bart Carl Earl>],
   'Earl' => [<Dave Fred>],
   'Fred' => [<Carl Gary>],
   'Gary' => ['Fred'],
   'Hank' => [<Earl Gary Hank>]
);

kosaraju(%test1);
say '';
kosaraju(%test2);
Output:
0 1 2
3 4
5 6
7

Andy Bart Carl
Dave Earl
Fred Gary
Hank

Phix

with javascript_semantics

sequence visited, l, t, c
 
procedure visit(sequence g, integer u)
    if not visited[u] then
        visited[u] = true
        for i=1 to length(g[u]) do
            integer v = g[u][i]
            visit(g,v)
            t[v] = deep_copy(t[v]) & u
        end for
        l &= u
    end if
end procedure
 
procedure assign(integer u, root=u)
    if visited[u] then
        visited[u] = false
        c[u] = root
        for v=1 to length(t[u]) do
            assign(t[u][v], root)
        end for
    end if
end procedure
 
function korasaju(sequence g)
    integer len = length(g)
    visited = repeat(false,len)
    l = {}
    t = repeat({},len)
    for u=1 to len do
        visit(g,u)
    end for
    c = repeat(0,len)
    for u=length(l) to 1 by -1 do
        assign(l[u])
    end for
    return c
end function
 
constant g = {{2}, {3}, {1}, {2, 3, 5}, {4, 6}, {3, 7}, {6}, {5, 7, 8}}
?korasaju(g)
Output:
{1,1,1,4,4,6,6,8}

Python

Works with Python 2

def kosaraju(g):
    class nonlocal: pass

    # 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    size = len(g)

    vis = [False]*size # vertexes that have been visited
    l = [0]*size
    nonlocal.x = size
    t = [[]]*size   # transpose graph

    def visit(u):
        if not vis[u]:
            vis[u] = True
            for v in g[u]:
                visit(v)
                t[v] = t[v] + [u]
            nonlocal.x = nonlocal.x - 1
            l[nonlocal.x] = u

    # 2. For each vertex u of the graph do visit(u)
    for u in range(len(g)):
        visit(u)
    c = [0]*size

    def assign(u, root):
        if vis[u]:
            vis[u] = False
            c[u] = root
            for v in t[u]:
                assign(v, root)

    # 3: For each element u of l in order, do assign(u, u)
    for u in l:
        assign(u, u)

    return c

g = [[1], [2], [0], [1,2,4], [3,5], [2,6], [5], [4,6,7]]
print kosaraju(g)
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Syntax requirements have changed. This version works with Python 3.

def kosaraju(g):
    size = len(g)
    vis = [False] * size
    l = [0] * size
    x = size
    t = [[] for _ in range(size)]

    def visit(u):
        nonlocal x
        if not vis[u]:
            vis[u] = True
            for v in g[u]:
                visit(v)
                t[v].append(u)
            x -= 1
            l[x] = u

    for u in range(size):
        visit(u)
    c = [0] * size

    def assign(u, root):
        if vis[u]:
            vis[u] = False
            c[u] = root
            for v in t[u]:
                assign(v, root)

    for u in l:
        assign(u, u)

    return c


g = [[1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7]]
print(kosaraju(g))
Output:
[0, 0, 0, 3, 3, 5, 5, 7]


Racket

#lang racket

(require racket/dict)

;; G is a dictionary of vertex -> (list vertex)
(define (Kosuraju G)
  (letrec
      ((vertices (remove-duplicates (append (dict-keys G) (append* (dict-values G)))))
       (visited?-dict (make-hash)) ; or any mutable dict type
       (assigned-dict (make-hash)) ; or any mutable dict type
       (neighbours:in (λ (u) (for/list (([v outs] (in-dict G)) #:when (member u outs)) v)))  
       (visit! (λ (u L)
                 (cond [(dict-ref visited?-dict u #f) L]
                       [else (dict-set! visited?-dict u #t)
                             (cons u (for/fold ((L L)) ((v (in-list (dict-ref G u)))) (visit! v L)))])))  
       (assign! (λ (u root)
                  (unless (dict-ref assigned-dict u #f)
                    (dict-set! assigned-dict u root)
                    (for ((v (in-list (neighbours:in u)))) (assign! v root)))))
       (L (for/fold ((l null)) ((u (in-dict-keys G))) (visit! u l))))
    
    (for ((u (in-list L))) (assign! u u))  
    (map (curry map car) (group-by cdr (dict->list assigned-dict) =))))

(module+ test
  (Kosuraju '((0 1)
              (2 0)
              (5 2 6)
              (6 5)
              (1 2)
              (3 1 2 4) ; equvalent to (3 . (1 2 4))
              (4 5 3)
              (7 4 7 6))))
Output:
'((7) (6 5) (4 3) (2 1 0))

Raku

(formerly Perl 6)

Works with: Rakudo version 2018.09

Inspired by Python & Kotlin entries.

Accepts a hash of lists/arrays holding the vertex (name => (neighbors)) pairs. No longer limited to continuous, positive, integer vertex names.

sub kosaraju (%k) {
    my %g = %k.keys.sort Z=> flat ^%k;
    my %h = %g.invert;
    my %visited;
    my @stack;
    my @transpose;
    my @connected;
 
    sub visit ($u) {
        unless %visited{$u} {
            %visited{$u} = True;
            for |%k{$u} -> $v {
                visit($v);
                @transpose[%g{$v}].push: $u;
            }
            @stack.push: $u;
        }
    }
 
    sub assign ($u, $root) {
        if %visited{$u} {
            %visited{$u}   = False;
            @connected[%g{$u}] = $root;
            assign($_, $root) for |@transpose[%g{$u}];
        }
    }
 
    .&visit for %g.keys;
    assign($_, $_) for @stack.reverse;

    (|%g{@connected}).pairs.categorize( *.value, :as(*.key) ).values.map: { %h{|$_} };
}

# TESTING

-> $test { say "\nStrongly connected components: ", |kosaraju($test).sort } for

# Same test data as all other entries, converted to a hash of lists
(((1),(2),(0),(1,2,4),(3,5),(2,6),(5),(4,6,7)).pairs.hash),

# Same layout test data with named vertices instead of numbered.
(
 %(:Andy<Bart>,
   :Bart<Carl>,
   :Carl<Andy>,
   :Dave<Bart Carl Earl>,
   :Earl<Dave Fred>,
   :Fred<Carl Gary>,
   :Gary<Fred>,
   :Hank<Earl Gary Hank>)
)
Output:
Strongly connected components: (0 1 2)(3 4)(5 6)(7)

Strongly connected components: (Andy Bart Carl)(Dave Earl)(Fred Gary)(Hank)

Sidef

Translation of: Julia
func korasaju(Array g) {
    # 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    var vis = g.len.of(false)
    var L   = []
    var x   = g.end
    var t   = g.len.of { [] }

    # Recursive
    func visit(u) {
        if (!vis[u]) {
            vis[u] = true
            g[u].each {|v|
                visit(v)
                t[v] << u
            }
            L[x--] = u
        }
    }

    # 2. For each vertex u of the graph do visit(u)
    g.range.each {|u|
        visit(u)
    }

    var c = []

    # 3. Recursive subroutine:
    func assign(u, root) {
        if (vis[u]) {
            vis[u] = false
            c[u] = root
            t[u].each {|v|
                assign(v, root)
            }
        }
    }

    # 3. For each element u of L in order, do assign(u, u)
    L.each {|u|
        assign(u, u)
    }

    return c
}

var g = [[1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7]]
say korasaju(g)
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Standard ML

datatype 'a node = Node of 'a * bool ref * 'a node list ref * 'a node list ref

fun node x = Node (x, ref false, ref nil, ref nil)
fun mark (Node (_, r, _, _)) = !r before r := true
fun unmark (Node (_, r, _, _)) = !r before r := false

fun value (Node (x, _, _, _)) = x
fun sources (Node (_, _, ref xs, _)) = xs
fun targets (Node (_, _, _, ref ys)) = ys

fun connect (m, n) =
  let
    val Node (_, _, _, ns) = m
    val Node (_, _, ms, _) = n
  in
    ms := m :: !ms;
    ns := n :: !ns
  end

datatype 'a step = One of 'a | Many of 'a list

fun visit (ms, nil) = ms
  | visit (ms, One m :: ss) = visit (m :: ms, ss)
  | visit (ms, Many nil :: ss) = visit (ms, ss)
  | visit (ms, Many (n :: ns) :: ss) =
    if mark n then
      visit (ms, Many ns :: ss)
    else
      visit (ms, Many (targets n) :: One n :: Many ns :: ss)

fun assign (xs, nil) = xs
  | assign (xs, nil :: ss) = assign (xs, ss)
  | assign (xs, (n :: ns) :: ss) =
    if unmark n then
      assign (value n :: xs, sources n :: ns :: ss)
    else
      assign (xs, ns :: ss)

fun assigns (xs, nil) = xs
  | assigns (xs, n :: ns) =
    if unmark n then
      let
        val x = sources n :: nil
        val x = value n :: assign (nil, x)
      in
        assigns (x :: xs, ns)
      end
    else
      assigns (xs, ns)

fun kosaraju xs = assigns (nil, visit (nil, Many xs :: nil))

fun make (n, is, ijs) =
  let
    val xs = Vector.tabulate (n, node)
    fun item i = Vector.sub (xs, i)
    fun step (i, j) = connect (item i, item j)
    fun path (i :: j :: js) = (step (i, j); path (j :: js))
      | path _ = ()
  in
    map item is before app path ijs
  end

val is = 0 :: nil
val ijs =
  [0, 1, 2, 0, 3, 4, 0, 5, 7] ::
  [0, 9, 10, 11, 12, 9, 11] ::
  [1, 12] ::
  [3, 5, 6, 7, 8, 6, 15] ::
  [5, 13, 14, 13, 15] ::
  [8, 15] ::
  [10, 13] ::
  nil

val ns = make (16, is, ijs)
val xs = kosaraju ns
Output:
> xs;
val it = [[15], [13, 14], [9, 10, 11, 12], [6, 7, 8], [5], [0, 1, 2, 3, 4]]: int list list

Swift

Translation of: D
func kosaraju(graph: [[Int]]) -> [Int] {
  let size = graph.count
  var x = size
  var vis = [Bool](repeating: false, count: size)
  var l = [Int](repeating: 0, count: size)
  var c = [Int](repeating: 0, count: size)
  var t = [[Int]](repeating: [], count: size)

  func visit(_ u: Int) {
    guard !vis[u] else {
      return
    }

    vis[u] = true

    for v in graph[u] {
      visit(v)
      t[v].append(u)
    }

    x -= 1
    l[x] = u
  }

  for u in 0..<graph.count {
    visit(u)
  }

  func assign(_ u: Int, root: Int) {
    guard vis[u] else {
      return
    }

    vis[u] = false
    c[u] = root

    for v in t[u] {
      assign(v, root: root)
    }
  }

  for u in l {
    assign(u, root: u)
  }

  return c
}

let graph = [
  [1],
  [2],
  [0],
  [1, 2, 4],
  [3, 5],
  [2, 6],
  [5],
  [4, 6, 7]
]

print(kosaraju(graph: graph))
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Visual Basic .NET

Translation of: Java
Module Module1

    Function Kosaraju(g As List(Of List(Of Integer))) As List(Of Integer)
        Dim size = g.Count
        Dim vis(size - 1) As Boolean
        Dim l(size - 1) As Integer
        Dim x = size

        Dim t As New List(Of List(Of Integer))
        For i = 1 To size
            t.Add(New List(Of Integer))
        Next

        Dim visit As Action(Of Integer) = Sub(u As Integer)
                                              If Not vis(u) Then
                                                  vis(u) = True
                                                  For Each v In g(u)
                                                      visit(v)
                                                      t(v).Add(u)
                                                  Next
                                                  x -= 1
                                                  l(x) = u
                                              End If
                                          End Sub

        For i = 1 To size
            visit(i - 1)
        Next
        Dim c(size - 1) As Integer

        Dim assign As Action(Of Integer, Integer) = Sub(u As Integer, root As Integer)
                                                        If vis(u) Then
                                                            vis(u) = False
                                                            c(u) = root
                                                            For Each v In t(u)
                                                                assign(v, root)
                                                            Next
                                                        End If
                                                    End Sub

        For Each u In l
            assign(u, u)
        Next

        Return c.ToList
    End Function

    Sub Main()
        Dim g = New List(Of List(Of Integer)) From {
            New List(Of Integer) From {1},
            New List(Of Integer) From {2},
            New List(Of Integer) From {0},
            New List(Of Integer) From {1, 2, 4},
            New List(Of Integer) From {3, 5},
            New List(Of Integer) From {2, 6},
            New List(Of Integer) From {5},
            New List(Of Integer) From {4, 6, 7}
        }

        Dim output = Kosaraju(g)
        Console.WriteLine("[{0}]", String.Join(", ", output))
    End Sub

End Module
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

Wren

Translation of: Go
var kosaraju = Fn.new { |g|
    var gc = g.count
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    var vis = List.filled(gc, false)
    var l = List.filled(gc, 0)
    var x = gc                     // index for filling l in reverse order
    var t = List.filled(gc, null)  // transpose graph
    for (i in 0...gc) t[i] = []
    var visit // recursive function
    visit = Fn.new { |u|
        if (!vis[u]) {
            vis[u] = true
            for (v in g[u]) {
                visit.call(v)
                t[v].add(u)  // construct transpose
            }
            x = x - 1
            l[x] = u
        }
    }
    // 2. For each vertex u of the graph do visit.call(u).
    for (i in 0...gc) visit.call(i)  
    var c = List.filled(gc, 0) // result, the component assignment
    var assign // recursive function
    assign = Fn.new { |u, root|
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for (v in t[u]) assign.call(v, root)
        }
    }
    // 3: For each element u of l in order, do assign.call(u,u).
    for (u in l) assign.call(u, u)
    return c
}

var g = [ [1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7] ]
System.print(kosaraju.call(g))
Output:
[0, 0, 0, 3, 3, 5, 5, 7]

zkl

const VISITED=0,ASSIGNED=1;

fcn visit(u,G,L){	// u is ((visited,assigned), (id,edges))
   u0:=u[0];
   if(u0[VISITED]) return();
   u0[VISITED]=True;
   foreach idx in (u[1][1,*]){ visit(G[idx],G,L) } // vist out-neighbours
   L.insert(0,u);	// prepend u to L
}
fcn assign(u,root,G){  // u as above, root is a list of strong components
   u0:=u[0];
   if(u0[ASSIGNED]) return();
   root.append(u[1][0]);
   u0[ASSIGNED]=True;
   uid:=u[1][0];
   foreach v in (G){  // traverse graph to find in-neighbours, fugly
      n,ins := v[1][0],v[1][1,*];
      if(ins.holds(uid)) assign(G[n],root,G); // assign in-neighbour
   } 
}
fcn kosaraju(graph){  // Use Tarjan's algorithm instead of this one
   // input: graph G = (V, Es)
   // output: set of strongly connected components (sets of vertices)

   // convert graph to ( (index,lowlink,onStack),(id,links)), ...)
   // sorted by id
   G:=List.createLong(graph.len(),0);
   foreach v in (graph){ G[v[0]]=T( List(False,False),v) }

   L:=List();
   foreach u in (G){ visit(u,G,L) }

   components:=List.createLong(graph.len(),List.copy,True);
   foreach u in (L){ assign(u,components[u[1][0]],G) }
   components=components.filter();

   println("List of strongly connected components:");
   foreach c in (components){ println(c.reverse().concat(",")) }

   return(components);
}
   // graph from https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
   // with vertices id zero based (vs 1 based in article)
   // ids start at zero and are consecutive (no holes), graph is unsorted
graph:=	  // ( (id, links/Edges), ...)
   T( T(0,1), T(2,0),     T(5,2,6), T(6,5),
      T(1,2), T(3,1,2,4), T(4,5,3), T(7,4,7,6) );
kosaraju(graph);
Output:
List of strongly connected components:
1,2,0
4,3
6,5
7
Cookies help us deliver our services. By using our services, you agree to our use of cookies.