Open In App

Tarjan’s Algorithm to find Strongly Connected Components

Last Updated : 06 Jun, 2023
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Save
Share
Report
News Follow
Companies:
Show Topics
Solve Problem
Hard
36.78%
26.9K

A directed graph is strongly connected if there is a path between all pairs of vertices. A strongly connected component (SCC) of a directed graph is a maximal strongly connected subgraph. For example, there are 3 SCCs in the following graph:

SCC

We have discussed Kosaraju’s algorithm for strongly connected components. The previously discussed algorithm requires two DFS traversals of a Graph. In this post, Tarjan’s algorithm is discussed that requires only one DFS traversal:

Tarjan Algorithm is based on the following facts: 

  • DFS search produces a DFS tree/forest 
  • Strongly Connected Components form subtrees of the DFS tree. 
  • If we can find the head of such subtrees, we can print/store all the nodes in that subtree (including the head) and that will be one SCC. 
  • There is no back edge from one SCC to another (There can be cross edges, but cross edges will not be used while processing the graph).

To find the head of an SCC, we calculate the disc and low array (as done for articulation point, bridge, and biconnected component). As discussed in the previous posts, low[u] indicates the earliest visited vertex (the vertex with minimum discovery time) that can be reached from a subtree rooted with u. A node u is head if disc[u] = low[u]

Below is an illustration of the above approach:  

To solve the problem follow the below idea:

Strongly Connected Component relates to directed graph only, but Disc and Low values relate to both directed and undirected graph, so in the above pic we have taken an undirected graph.

In the above Figure, we have shown a graph and one of the DFS trees (There could be different DFS trees on the same graph depending on the order in which edges are traversed). In a DFS tree, continuous arrows are tree edges, and dashed arrows are back edges (DFS Tree Edges ). Disc and Low values are shown in the Figure for every node as (Disc/Low). 

Disc: This is the time when a node is visited 1st time while DFS traversal. For nodes A, B, C, .., and J in the DFS tree, Disc values are 1, 2, 3, .., 10. 

Low: In the DFS tree, Tree edges take us forward, from the ancestor node to one of its descendants. For example, from node C, tree edges can take us to node G, node I, etc. Back edges take us backward, from a descendant node to one of its ancestors. 

For example: From node G, the Back edges take us to E or C. If we look at both the Tree and Back edges together, then we can see that if we start traversal from one node, we may go down the tree via Tree edges and then go up via back edges. 

For example, from node E, we can go down to G and then go up to C. Similarly from E, we can go down to I or J and then go up to F. “Low” value of a node tells the topmost reachable ancestor (with minimum possible Disc value) via the subtree of that node. So for any node, a Low value is equal to its Disc value anyway (A node is the ancestor of itself). Then we look into its subtree and see if there is any node that can take us to any of its ancestors. 

If there are multiple back edges in the subtree that take us to different ancestors, then we take the one with the minimum Disc value (i.e. the topmost one). If we look at node F, it has two subtrees. Subtree with node G takes us to E and C. The other subtree takes us back to F only. Here topmost ancestor is C where F can reach and so the Low value of F is 3 (The Disc value of C). 

Based on the above discussion, it should be clear that the Low values of B, C, and D are 1 (As A is the topmost node where B, C, and D can reach). In the same way, the Low values of E, F, and G are 3, and the Low values of H, I, and J are 6.
For any node u, when DFS starts, Low will be set to its Disc 1st

Then later on DFS will be performed on each of its children v one by one, Low value of u can change in two cases: 

  • Case1 (Tree Edge): If node v is not visited already, then after the DFS of v is complete, a minimum of low[u] and low[v] will be updated to low[u]. 
    low[u] = min(low[u], low[v]); 
  • Case 2 (Back Edge): When child v is already visited, then a minimum of low[u] and Disc[v] will be updated to low[u]. 
    low[u] = min(low[u], disc[v]); 

In case two, can we take low[v] instead of the disc[v] ?? The answer is NO. If you can think why the answer is NO, you probably understood the Low and Disc concept.

edge-types

Same Low and Disc values help to solve other graph problems like articulation point, bridge, and biconnected component. To track the subtree rooted at the head, we can use a stack (keep pushing the node while visiting). When a head node is found, pop all nodes from the stack till you get the head out of the stack. To make sure, we don’t consider cross edges, when we reach a node that is already visited, we should process the visited node only if it is present in the stack, or else ignore the node.  

Below is the implementation of Tarjan’s algorithm to print all SCCs. 

C++




// A C++ program to find strongly connected components in a
// given directed graph using Tarjan's algorithm (single
// DFS)
#include <bits/stdc++.h>
#define NIL -1
using namespace std;
 
// A class that represents an directed graph
class Graph {
    int V; // No. of vertices
    list<int>* adj; // A dynamic array of adjacency lists
 
    // A Recursive DFS based function used by SCC()
    void SCCUtil(int u, int disc[], int low[],
                 stack<int>* st, bool stackMember[]);
 
public:
    Graph(int V); // Constructor
    void addEdge(int v,
                 int w); // function to add an edge to graph
    void SCC(); // prints strongly connected components
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}
 
void Graph::addEdge(int v, int w) { adj[v].push_back(w); }
 
// A recursive function that finds and prints strongly
// connected components using DFS traversal u --> The vertex
// to be visited next disc[] --> Stores discovery times of
// visited vertices low[] -- >> earliest visited vertex (the
// vertex with minimum
//             discovery time) that can be reached from
//             subtree rooted with current vertex
// *st -- >> To store all the connected ancestors (could be
// part
//         of SCC)
// stackMember[] --> bit/index array for faster check
// whether
//                 a node is in stack
void Graph::SCCUtil(int u, int disc[], int low[],
                    stack<int>* st, bool stackMember[])
{
    // A static variable is used for simplicity, we can
    // avoid use of static variable by passing a pointer.
    static int time = 0;
 
    // Initialize discovery time and low value
    disc[u] = low[u] = ++time;
    st->push(u);
    stackMember[u] = true;
 
    // Go through all vertices adjacent to this
    list<int>::iterator i;
    for (i = adj[u].begin(); i != adj[u].end(); ++i) {
        int v = *i; // v is current adjacent of 'u'
 
        // If v is not visited yet, then recur for it
        if (disc[v] == -1) {
            SCCUtil(v, disc, low, st, stackMember);
 
            // Check if the subtree rooted with 'v' has a
            // connection to one of the ancestors of 'u'
            // Case 1 (per above discussion on Disc and Low
            // value)
            low[u] = min(low[u], low[v]);
        }
 
        // Update low value of 'u' only of 'v' is still in
        // stack (i.e. it's a back edge, not cross edge).
        // Case 2 (per above discussion on Disc and Low
        // value)
        else if (stackMember[v] == true)
            low[u] = min(low[u], disc[v]);
    }
 
    // head node found, pop the stack and print an SCC
    int w = 0; // To store stack extracted vertices
    if (low[u] == disc[u]) {
        while (st->top() != u) {
            w = (int)st->top();
            cout << w << " ";
            stackMember[w] = false;
            st->pop();
        }
        w = (int)st->top();
        cout << w << "\n";
        stackMember[w] = false;
        st->pop();
    }
}
 
// The function to do DFS traversal. It uses SCCUtil()
void Graph::SCC()
{
    int* disc = new int[V];
    int* low = new int[V];
    bool* stackMember = new bool[V];
    stack<int>* st = new stack<int>();
 
    // Initialize disc and low, and stackMember arrays
    for (int i = 0; i < V; i++) {
        disc[i] = NIL;
        low[i] = NIL;
        stackMember[i] = false;
    }
 
    // Call the recursive helper function to find strongly
    // connected components in DFS tree with vertex 'i'
    for (int i = 0; i < V; i++)
        if (disc[i] == NIL)
            SCCUtil(i, disc, low, st, stackMember);
}
 
// Driver program to test above function
int main()
{
    cout << "\nSCCs in first graph \n";
    Graph g1(5);
    g1.addEdge(1, 0);
    g1.addEdge(0, 2);
    g1.addEdge(2, 1);
    g1.addEdge(0, 3);
    g1.addEdge(3, 4);
    g1.SCC();
 
    cout << "\nSCCs in second graph \n";
    Graph g2(4);
    g2.addEdge(0, 1);
    g2.addEdge(1, 2);
    g2.addEdge(2, 3);
    g2.SCC();
 
    cout << "\nSCCs in third graph \n";
    Graph g3(7);
    g3.addEdge(0, 1);
    g3.addEdge(1, 2);
    g3.addEdge(2, 0);
    g3.addEdge(1, 3);
    g3.addEdge(1, 4);
    g3.addEdge(1, 6);
    g3.addEdge(3, 5);
    g3.addEdge(4, 5);
    g3.SCC();
 
    cout << "\nSCCs in fourth graph \n";
    Graph g4(11);
    g4.addEdge(0, 1);
    g4.addEdge(0, 3);
    g4.addEdge(1, 2);
    g4.addEdge(1, 4);
    g4.addEdge(2, 0);
    g4.addEdge(2, 6);
    g4.addEdge(3, 2);
    g4.addEdge(4, 5);
    g4.addEdge(4, 6);
    g4.addEdge(5, 6);
    g4.addEdge(5, 7);
    g4.addEdge(5, 8);
    g4.addEdge(5, 9);
    g4.addEdge(6, 4);
    g4.addEdge(7, 9);
    g4.addEdge(8, 9);
    g4.addEdge(9, 8);
    g4.SCC();
 
    cout << "\nSCCs in fifth graph \n";
    Graph g5(5);
    g5.addEdge(0, 1);
    g5.addEdge(1, 2);
    g5.addEdge(2, 3);
    g5.addEdge(2, 4);
    g5.addEdge(3, 0);
    g5.addEdge(4, 2);
    g5.SCC();
 
    return 0;
}


Java




// Java program to find strongly connected
// components in a given directed graph
// using Tarjan's algorithm (single DFS)
import java.io.*;
import java.util.*;
 
// This class represents a directed graph
// using adjacency list representation
class Graph {
 
    // No. of vertices
    private int V;
 
    // Adjacency Lists
    private LinkedList<Integer> adj[];
    private int Time;
 
    // Constructor
    @SuppressWarnings("unchecked") Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
 
        for (int i = 0; i < v; ++i)
            adj[i] = new LinkedList();
 
        Time = 0;
    }
 
    // Function to add an edge into the graph
    void addEdge(int v, int w) { adj[v].add(w); }
 
    // A recursive function that finds and prints strongly
    // connected components using DFS traversal
    // u --> The vertex to be visited next
    // disc[] --> Stores discovery times of visited vertices
    // low[] -- >> earliest visited vertex (the vertex with
    //             minimum discovery time) that can be
    //             reached from subtree rooted with current
    //             vertex
    // st -- >> To store all the connected ancestors (could
    // be part
    //         of SCC)
    // stackMember[] --> bit/index array for faster check
    //                   whether a node is in stack
    void SCCUtil(int u, int low[], int disc[],
                 boolean stackMember[], Stack<Integer> st)
    {
 
        // Initialize discovery time and low value
        disc[u] = Time;
        low[u] = Time;
        Time += 1;
        stackMember[u] = true;
        st.push(u);
 
        int n;
 
        // Go through all vertices adjacent to this
        Iterator<Integer> i = adj[u].iterator();
 
        while (i.hasNext()) {
            n = i.next();
 
            if (disc[n] == -1) {
                SCCUtil(n, low, disc, stackMember, st);
 
                // Check if the subtree rooted with v
                // has a connection to one of the
                // ancestors of u
                // Case 1 (per above discussion on
                // Disc and Low value)
                low[u] = Math.min(low[u], low[n]);
            }
            else if (stackMember[n] == true) {
 
                // Update low value of 'u' only if 'v' is
                // still in stack (i.e. it's a back edge,
                // not cross edge).
                // Case 2 (per above discussion on Disc
                // and Low value)
                low[u] = Math.min(low[u], disc[n]);
            }
        }
 
        // head node found, pop the stack and print an SCC
        // To store stack extracted vertices
        int w = -1;
        if (low[u] == disc[u]) {
            while (w != u) {
                w = (int)st.pop();
                System.out.print(w + " ");
                stackMember[w] = false;
            }
            System.out.println();
        }
    }
 
    // The function to do DFS traversal.
    // It uses SCCUtil()
    void SCC()
    {
 
        // Mark all the vertices as not visited
        // and Initialize parent and visited,
        // and ap(articulation point) arrays
        int disc[] = new int[V];
        int low[] = new int[V];
        for (int i = 0; i < V; i++) {
            disc[i] = -1;
            low[i] = -1;
        }
 
        boolean stackMember[] = new boolean[V];
        Stack<Integer> st = new Stack<Integer>();
 
        // Call the recursive helper function
        // to find articulation points
        // in DFS tree rooted with vertex 'i'
        for (int i = 0; i < V; i++) {
            if (disc[i] == -1)
                SCCUtil(i, low, disc, stackMember, st);
        }
    }
 
    // Driver code
    public static void main(String args[])
    {
 
        // Create a graph given in the above diagram
        Graph g1 = new Graph(5);
 
        g1.addEdge(1, 0);
        g1.addEdge(0, 2);
        g1.addEdge(2, 1);
        g1.addEdge(0, 3);
        g1.addEdge(3, 4);
        System.out.println("SSC in first graph ");
        g1.SCC();
 
        Graph g2 = new Graph(4);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        g2.addEdge(2, 3);
        System.out.println("\nSSC in second graph ");
        g2.SCC();
 
        Graph g3 = new Graph(7);
        g3.addEdge(0, 1);
        g3.addEdge(1, 2);
        g3.addEdge(2, 0);
        g3.addEdge(1, 3);
        g3.addEdge(1, 4);
        g3.addEdge(1, 6);
        g3.addEdge(3, 5);
        g3.addEdge(4, 5);
        System.out.println("\nSSC in third graph ");
        g3.SCC();
 
        Graph g4 = new Graph(11);
        g4.addEdge(0, 1);
        g4.addEdge(0, 3);
        g4.addEdge(1, 2);
        g4.addEdge(1, 4);
        g4.addEdge(2, 0);
        g4.addEdge(2, 6);
        g4.addEdge(3, 2);
        g4.addEdge(4, 5);
        g4.addEdge(4, 6);
        g4.addEdge(5, 6);
        g4.addEdge(5, 7);
        g4.addEdge(5, 8);
        g4.addEdge(5, 9);
        g4.addEdge(6, 4);
        g4.addEdge(7, 9);
        g4.addEdge(8, 9);
        g4.addEdge(9, 8);
        System.out.println("\nSSC in fourth graph ");
        g4.SCC();
 
        Graph g5 = new Graph(5);
        g5.addEdge(0, 1);
        g5.addEdge(1, 2);
        g5.addEdge(2, 3);
        g5.addEdge(2, 4);
        g5.addEdge(3, 0);
        g5.addEdge(4, 2);
        System.out.println("\nSSC in fifth graph ");
        g5.SCC();
    }
}
 
// This code is contributed by
// Prateek Gupta (@prateekgupta10)


Python3




# Python program to find strongly connected components in a given
# directed graph using Tarjan's algorithm (single DFS)
#Complexity : O(V+E)
 
from collections import defaultdict
 
# This class represents an directed graph
# using adjacency list representation
 
 
class Graph:
 
    def __init__(self, vertices):
        # No. of vertices
        self.V = vertices
 
        # default dictionary to store graph
        self.graph = defaultdict(list)
 
        self.Time = 0
 
    # function to add an edge to graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
 
    '''A recursive function that find finds and prints strongly connected
    components using DFS traversal
    u --> The vertex to be visited next
    disc[] --> Stores discovery times of visited vertices
    low[] -- >> earliest visited vertex (the vertex with minimum
                discovery time) that can be reached from subtree
                rooted with current vertex
     st -- >> To store all the connected ancestors (could be part
           of SCC)
     stackMember[] --> bit/index array for faster check whether
                  a node is in stack
    '''
 
    def SCCUtil(self, u, low, disc, stackMember, st):
 
        # Initialize discovery time and low value
        disc[u] = self.Time
        low[u] = self.Time
        self.Time += 1
        stackMember[u] = True
        st.append(u)
 
        # Go through all vertices adjacent to this
        for v in self.graph[u]:
 
            # If v is not visited yet, then recur for it
            if disc[v] == -1:
 
                self.SCCUtil(v, low, disc, stackMember, st)
 
                # Check if the subtree rooted with v has a connection to
                # one of the ancestors of u
                # Case 1 (per above discussion on Disc and Low value)
                low[u] = min(low[u], low[v])
 
            elif stackMember[v] == True:
 
                '''Update low value of 'u' only if 'v' is still in stack
                (i.e. it's a back edge, not cross edge).
                Case 2 (per above discussion on Disc and Low value) '''
                low[u] = min(low[u], disc[v])
 
        # head node found, pop the stack and print an SCC
        w = -1  # To store stack extracted vertices
        if low[u] == disc[u]:
            while w != u:
                w = st.pop()
                print(w, end=" ")
                stackMember[w] = False
 
            print()
 
    # The function to do DFS traversal.
    # It uses recursive SCCUtil()
 
    def SCC(self):
 
        # Mark all the vertices as not visited
        # and Initialize parent and visited,
        # and ap(articulation point) arrays
        disc = [-1] * (self.V)
        low = [-1] * (self.V)
        stackMember = [False] * (self.V)
        st = []
 
        # Call the recursive helper function
        # to find articulation points
        # in DFS tree rooted with vertex 'i'
        for i in range(self.V):
            if disc[i] == -1:
                self.SCCUtil(i, low, disc, stackMember, st)
 
 
# Create a graph given in the above diagram
g1 = Graph(5)
g1.addEdge(1, 0)
g1.addEdge(0, 2)
g1.addEdge(2, 1)
g1.addEdge(0, 3)
g1.addEdge(3, 4)
print("SSC in first graph ")
g1.SCC()
 
g2 = Graph(4)
g2.addEdge(0, 1)
g2.addEdge(1, 2)
g2.addEdge(2, 3)
print("\nSSC in second graph ")
g2.SCC()
 
 
g3 = Graph(7)
g3.addEdge(0, 1)
g3.addEdge(1, 2)
g3.addEdge(2, 0)
g3.addEdge(1, 3)
g3.addEdge(1, 4)
g3.addEdge(1, 6)
g3.addEdge(3, 5)
g3.addEdge(4, 5)
print("\nSSC in third graph ")
g3.SCC()
 
g4 = Graph(11)
g4.addEdge(0, 1)
g4.addEdge(0, 3)
g4.addEdge(1, 2)
g4.addEdge(1, 4)
g4.addEdge(2, 0)
g4.addEdge(2, 6)
g4.addEdge(3, 2)
g4.addEdge(4, 5)
g4.addEdge(4, 6)
g4.addEdge(5, 6)
g4.addEdge(5, 7)
g4.addEdge(5, 8)
g4.addEdge(5, 9)
g4.addEdge(6, 4)
g4.addEdge(7, 9)
g4.addEdge(8, 9)
g4.addEdge(9, 8)
print("\nSSC in fourth graph ")
g4.SCC()
 
 
g5 = Graph(5)
g5.addEdge(0, 1)
g5.addEdge(1, 2)
g5.addEdge(2, 3)
g5.addEdge(2, 4)
g5.addEdge(3, 0)
g5.addEdge(4, 2)
print("\nSSC in fifth graph ")
g5.SCC()
 
# This code is contributed by Neelam Yadav


Javascript




<script>
 
// Javascript program to find strongly connected
// components in a given directed graph
// using Tarjan's algorithm (single DFS)
 
// This class represents a directed graph
// using adjacency list representation
class Graph{
     
// Constructor
constructor(v)
{
    this.V = v;
    this.adj = new Array(v);
   
    for(let i = 0; i < v; ++i)
        this.adj[i] = [];
       
    this.Time = 0;
}
 
// Function to add an edge into the graph
addEdge(v, w)
{
    this.adj[v].push(w);
}
 
// A recursive function that finds and prints strongly
// connected components using DFS traversal
// u --> The vertex to be visited next
// disc[] --> Stores discovery times of visited vertices
// low[] -- >> earliest visited vertex (the vertex with
//             minimum discovery time) that can be reached
//             from subtree rooted with current vertex
// st -- >> To store all the connected ancestors (could be
//          part of SCC)
// stackMember[] --> bit/index array for faster check
//                   whether a node is in stack
SCCUtil(u, low, disc, stackMember, st)
{
     
    // Initialize discovery time and low value
    disc[u] = this.Time;
    low[u] = this.Time;
    this.Time += 1;
    stackMember[u] = true;
    st.push(u);
   
    let n;
       
    // Go through all vertices adjacent to this
    for(let i of this.adj[u])
    {
        n = i;
           
        if (disc[n] == -1)
        {
            this.SCCUtil(n, low, disc, stackMember, st);
               
            // Check if the subtree rooted with v
            // has a connection to one of the
            // ancestors of u
            // Case 1 (per above discussion on
            // Disc and Low value)
            low[u] = Math.min(low[u], low[n]);
        }
        else if (stackMember[n] == true)
        {
               
            // Update low value of 'u' only if 'v' is
            // still in stack (i.e. it's a back edge,
            // not cross edge).
            // Case 2 (per above discussion on Disc
            // and Low value)
            low[u] = Math.min(low[u], disc[n]);
        }
    }
   
    // Head node found, pop the stack and print an SCC
    // To store stack extracted vertices
    let w = -1;
    if (low[u] == disc[u])
    {
        while (w != u)
        {
            w = st.pop();
            document.write(w + " ");
            stackMember[w] = false;
        }
        document.write("<br>");
    }
    }
     
// The function to do DFS traversal.
// It uses SCCUtil()
SCC()
{
     
    // Mark all the vertices as not visited
    // and Initialize parent and visited,
    // and ap(articulation point) arrays
    let disc = new Array(this.V);
    let low = new Array(this.V);
    for(let i = 0;i < this.V; i++)
    {
        disc[i] = -1;
        low[i] = -1;
    }
       
    let stackMember = new Array(this.V);
    let st = [];
       
    // Call the recursive helper function
    // to find articulation points
    // in DFS tree rooted with vertex 'i'
    for(let i = 0; i < this.V; i++)
    {
        if (disc[i] == -1)
            this.SCCUtil(i, low, disc,
                         stackMember, st);
    }
}
}
 
// Driver code
 
// Create a graph given in the above diagram
let g1 = new Graph(5);
 
g1.addEdge(1, 0);
g1.addEdge(0, 2);
g1.addEdge(2, 1);
g1.addEdge(0, 3);
g1.addEdge(3, 4);
document.write("SSC in first graph <br>");
g1.SCC();
 
let g2 = new Graph(4);
g2.addEdge(0, 1);
g2.addEdge(1, 2);
g2.addEdge(2, 3);
document.write("\nSSC in second graph<br> ");
g2.SCC();
 
let g3 = new Graph(7);
g3.addEdge(0, 1);
g3.addEdge(1, 2);
g3.addEdge(2, 0);
g3.addEdge(1, 3);
g3.addEdge(1, 4);
g3.addEdge(1, 6);
g3.addEdge(3, 5);
g3.addEdge(4, 5);
document.write("\nSSC in third graph <br>");
g3.SCC();
 
let g4 = new Graph(11);
g4.addEdge(0, 1);
g4.addEdge(0, 3);
g4.addEdge(1, 2);
g4.addEdge(1, 4);
g4.addEdge(2, 0);
g4.addEdge(2, 6);
g4.addEdge(3, 2);
g4.addEdge(4, 5);
g4.addEdge(4, 6);
g4.addEdge(5, 6);
g4.addEdge(5, 7);
g4.addEdge(5, 8);
g4.addEdge(5, 9);
g4.addEdge(6, 4);
g4.addEdge(7, 9);
g4.addEdge(8, 9);
g4.addEdge(9, 8);
document.write("\nSSC in fourth graph<br> ");
g4.SCC();
 
let g5 = new Graph (5);
g5.addEdge(0, 1);
g5.addEdge(1, 2);
g5.addEdge(2, 3);
g5.addEdge(2, 4);
g5.addEdge(3, 0);
g5.addEdge(4, 2);
document.write("\nSSC in fifth graph <br>");
g5.SCC();
 
// This code is contributed by avanitrachhadiya2155
 
</script>


C#




using System;
using System.Collections.Generic;
 
// This class represents a directed graph
// using adjacency list representation
class Graph
{
    // No. of vertices
    private int V;
 
    // Adjacency Lists
    private List<int>[] adj;
    private int Time;
 
    // Constructor
    public Graph(int v)
    {
        V = v;
        adj = new List<int>[v];
 
        for (int i = 0; i < v; ++i)
            adj[i] = new List<int>();
 
        Time = 0;
    }
 
    // Function to add an edge into the graph
    public void addEdge(int v, int w) { adj[v].Add(w); }
 
    // A recursive function that finds and prints strongly
    // connected components using DFS traversal
    // u --> The vertex to be visited next
    // disc[] --> Stores discovery times of visited vertices
    // low[] -- >> earliest visited vertex (the vertex with
    //             minimum discovery time) that can be
    //             reached from subtree rooted with current
    //             vertex
    // st -- >> To store all the connected ancestors (could
    // be part
    //         of SCC)
    // stackMember[] --> bit/index array for faster check
    //                   whether a node is in stack
    private void SCCUtil(int u, int[] low, int[] disc,
                 bool[] stackMember, Stack<int> st)
    {
 
        // Initialize discovery time and low value
        disc[u] = Time;
        low[u] = Time;
        Time += 1;
        stackMember[u] = true;
        st.Push(u);
 
        int n;
 
        // Go through all vertices adjacent to this
        foreach (int i in adj[u])
        {
            n = i;
 
            if (disc[n] == -1)
            {
                SCCUtil(n, low, disc, stackMember, st);
 
                // Check if the subtree rooted with v
                // has a connection to one of the
                // ancestors of u
                // Case 1 (per above discussion on
                // Disc and Low value)
                low[u] = Math.Min(low[u], low[n]);
            }
            else if (stackMember[n] == true)
            {
                // Update low value of 'u' only if 'v' is
                // still in stack (i.e. it's a back edge,
                // not cross edge).
                // Case 2 (per above discussion on Disc
                // and Low value)
                low[u] = Math.Min(low[u], disc[n]);
            }
        }
 
        // head node found, pop the stack and print an SCC
        // To store stack extracted vertices
        int w = -1;
        if (low[u] == disc[u])
        {
            while (w != u)
            {
                w = st.Pop();
                Console.Write(w + " ");
                stackMember[w] = false;
            }
            Console.WriteLine();
        }
    }
 
    // The function to do DFS traversal.
    // It uses SCCUtil()
    public void SCC()
    {
        // Mark all the vertices as not visited
        // and Initialize parent and visited,
        // and ap(articulation point) arrays
        int[] disc = new int[V];
        int[] low = new int[V];
        for (int i = 0; i < V; i++)
        {
            disc[i] = -1;
            low[i] = -1;
        }
 
        bool[] stackMember = new bool[V];
        Stack<int> st = new Stack<int>();
            // Call the recursive helper function
    // to find strongly connected components
    for (int i = 0; i < V; i++)
        if (disc[i] == -1)
            SCCUtil(i, low, disc, stackMember, st);
}
static void Main(string[] args)
{
    // Create a new graph with 5 vertices
    Graph g = new Graph(5);
 
    // Add edges to the graph
    g.addEdge(1, 0);
    g.addEdge(0, 2);
    g.addEdge(2, 1);
    g.addEdge(0, 3);
    g.addEdge(3, 4);
 
    Console.WriteLine("Strongly Connected Components:");
    g.SCC();
     
        Graph g2 = new Graph(4);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        g2.addEdge(2, 3);
        Console.WriteLine("\nSSC in second graph ");
        g2.SCC();
 
        Graph g3 = new Graph(7);
        g3.addEdge(0, 1);
        g3.addEdge(1, 2);
        g3.addEdge(2, 0);
        g3.addEdge(1, 3);
        g3.addEdge(1, 4);
        g3.addEdge(1, 6);
        g3.addEdge(3, 5);
        g3.addEdge(4, 5);
      Console.WriteLine("\nSSC in third graph ");
        g3.SCC();
 
        Graph g4 = new Graph(11);
        g4.addEdge(0, 1);
        g4.addEdge(0, 3);
        g4.addEdge(1, 2);
        g4.addEdge(1, 4);
        g4.addEdge(2, 0);
        g4.addEdge(2, 6);
        g4.addEdge(3, 2);
        g4.addEdge(4, 5);
        g4.addEdge(4, 6);
        g4.addEdge(5, 6);
        g4.addEdge(5, 7);
        g4.addEdge(5, 8);
        g4.addEdge(5, 9);
        g4.addEdge(6, 4);
        g4.addEdge(7, 9);
        g4.addEdge(8, 9);
        g4.addEdge(9, 8);
        Console.WriteLine("\nSSC in fourth graph ");
        g4.SCC();
 
        Graph g5 = new Graph(5);
        g5.addEdge(0, 1);
        g5.addEdge(1, 2);
        g5.addEdge(2, 3);
        g5.addEdge(2, 4);
        g5.addEdge(3, 0);
        g5.addEdge(4, 2);
        Console.WriteLine("\nSSC in fifth graph ");
        g5.SCC();
}
}


Output

SCCs in first graph 
4
3
1 2 0

SCCs in second graph 
3
2
1
0

SCCs in third graph 
5
3
4
6
2 1 0

SCCs in fourth graph 
8 9
7
5 4 6
3 2 1 0
10

SCCs in fifth graph 
4 3 2 1 0

Time Complexity: The above algorithm mainly calls DFS, DFS takes O(V+E) for a graph represented using an adjacency list. 
Auxiliary Space: O(V)



Previous Article
Next Article

Similar Reads

Convert undirected connected graph to strongly connected directed graph
Given an undirected graph of N vertices and M edges, the task is to assign directions to the given M Edges such that the graph becomes Strongly Connected Components. If a graph cannot be converted into Strongly Connected Components then print "-1". Examples: Input: N = 5, Edges[][] = { { 0, 1 }, { 0, 2 }, { 1, 2 }, { 1, 4 }, { 2, 3 }, { 3, 4 } } Ou
14 min read
Strongly Connected Components (SCC) in Python
Strongly Connected Components (SCCs) in a directed graph are groups of vertices where each vertex has a path to every other vertex within the same group. SCCs are essential for understanding the connectivity structure of directed graphs. Kosaraju's Algorithm:Kosaraju's algorithm is a popular method for finding SCCs in a directed graph. It consists
3 min read
Strongly Connected Components
Strongly Connected Components (SCCs) are a fundamental concept in graph theory and algorithms. In a directed graph, a Strongly Connected Component is a subset of vertices where every vertex in the subset is reachable from every other vertex in the same subset by traversing the directed edges. Finding the SCCs of a graph can provide important insigh
15+ min read
Check if a graph is strongly connected | Set 1 (Kosaraju using DFS)
Given a directed graph, find out whether the graph is strongly connected or not. A directed graph is strongly connected if there is a path between any two pair of vertices. For example, following is a strongly connected graph. It is easy for undirected graph, we can just do a BFS and DFS starting from any vertex. If BFS or DFS visits all vertices,
13 min read
Strongly Connected Component meaning in DSA
Strongly Connected Component (SCC) is a concept in graph theory, specifically in directed graphs. A subgraph of a directed graph is considered to be an SCC if and only if for every pair of vertices A and B, there exists a path from A to B and a path from B to A. Properties of Strongly Connected Component:An SCC is a maximal strongly connected subgr
2 min read
Check if a given directed graph is strongly connected | Set 2 (Kosaraju using BFS)
Given a directed graph, find out whether the graph is strongly connected or not. A directed graph is strongly connected if there is a path between any two pairs of vertices. There are different methods to check the connectivity of directed graph but one of the optimized method is Kosaraju’s DFS based simple algorithm. Kosaraju’s BFS based simple al
14 min read
Minimum edges required to make a Directed Graph Strongly Connected
Given a Directed graph of N vertices and M edges, the task is to find the minimum number of edges required to make the given graph Strongly Connected. Examples:  Input: N = 3, M = 3, source[] = {1, 2, 1}, destination[] = {2, 3, 3} Output: 1 Explanation: Adding a directed edge joining the pair of vertices {3, 1} makes the graph strongly connected. H
10 min read
Comparison between Tarjan's and Kosaraju's Algorithm
Tarjan's Algorithm: The Tarjan's Algorithm is an efficient graph algorithm that is used to find the Strongly Connected Component(SCC) in a directed graph by using only one DFS traversal in linear time complexity. Working: Perform a DFS traversal over the nodes so that the sub-trees of the Strongly Connected Components are removed when they are enco
15+ min read
Tarjan's off-line lowest common ancestors algorithm
Prerequisite : LCA basics, Disjoint Set Union by Rank and Path CompressionWe are given a tree(can be extended to a DAG) and we have many queries of form LCA(u, v), i.e., find LCA of nodes ‘u’ and ‘v’.We can perform those queries in O(N + QlogN) time using RMQ, where O(N) time for pre-processing and O(log N) for answering the queries, where N = numb
15+ min read
Tarjan's Algorithm in Python
Tarjan's algorithm is used to find strongly connected components (SCCs) in a directed graph. It efficiently finds groups of vertices such that each vertex in a group has a path to every other vertex in the same group. Let's illustrate the working of Tarjan's algorithm with an example: Consider the following directed graph: 0 --> 1 --> 2 <-
2 min read
Queries to find number of connected grid components of given sizes in a Matrix
Given a matrix mat[][] containing only of 0s and 1s, and an array queries[], the task is for each query, say k, is to find the number of connected grid components (cells consisting of 1s) of size k. Note: Two cells are connected if they share an edge in the direction up, down, left, and right not diagonal. Example: Input: mat[][] = [[1 1 1 1 1 1],
14 min read
Find Weakly Connected Components in a Directed Graph
Weakly Connected Graph: A directed graph 'G = (V, E)' is weakly connected if the underlying undirected graph Ĝ is connected. The underlying undirected graph is the graph Ĝ = (V, Ê) where Ê represents the set of undirected edges that is obtained by removing the arrowheads from the directed edges and making them bidirectional in G. Example: The direc
9 min read
Number of connected components in a 2-D matrix of strings
Given a 2-D matrix mat[][] the task is to count the number of connected components in the matrix. A connected component is formed by all equal elements that share some common side with at least one other element of the same component.Examples: Input: mat[][] = {"bbba", "baaa"} Output: 2 The two connected components are: bbb b AND a aaa Input: mat[]
8 min read
Check if a Tree can be split into K equal connected components
Given Adjacency List representation of a tree and an integer K., the task is to find whether the given tree can be split into K equal Connected Components or not.Note: Two connected components are said to be equal if they contain equal number of nodes. Examples: Input: N = 15, K = 5 Below is the given tree with Number nodes = 15 Output: YES Explana
9 min read
Check if the length of all connected components is a Fibonacci number
Given an undirected graph with V vertices and E edges, the task is to find all the connected components of the graph and check if each of their lengths are a Fibonacci number or not. For example, consider the following graph. As depicted above, the lengths of the connected components are 2, 3, and 2 which are Fibonacci numbers. Examples: Input: E =
15+ min read
Count of unique lengths of connected components for an undirected graph using STL
Given an undirected graph, the task is to find the size of each connected component and print the number of unique sizes of connected components As depicted above, the count(size of the connected component) associated with the connected components is 2, 3, and 2. Now, the unique count of the components is 2 and 3. Hence, the expected result is Coun
10 min read
Maximum decimal equivalent possible among all connected components of a Binary Valued Graph
Given a binary-valued Undirected Graph with V vertices and E edges, the task is to find the maximum decimal equivalent among all the connected components of the graph. A binary-valued graph can be considered as having only binary numbers (0 or 1) as the vertex values. Examples: Input: E = 4, V = 7 Output: 3 Explanation: Decimal equivalents of the c
14 min read
Largest subarray sum of all connected components in undirected graph
Given an undirected graph with V vertices and E edges, the task is to find the maximum contiguous subarray sum among all the connected components of the graph. Examples: Input: E = 4, V = 7 Output: Maximum subarray sum among all connected components = 5 Explanation: Connected Components and maximum subarray sums are as follows: [3, 2]: Maximum suba
14 min read
Octal equivalents of connected components in Binary valued graph
Given a binary valued undirected graph with V vertices and E edges, the task is to find the octal equivalents of all the connected components of the graph. A binary valued graph can be considered as having only binary numbers (0 or 1) as the vertex values. Examples: Input: E = 4, V = 7 Output: Chain = 0 1 Octal equivalent = 1 Chain = 0 0 0 Octal eq
15+ min read
Queries to count connected components after removal of a vertex from a Tree
Given a Tree consisting of N nodes valued in the range [0, N) and an array Queries[] of Q integers consisting of values in the range [0, N). The task for each query is to remove the vertex valued Q[i] and count the connected components in the resulting graph. Examples: Input: N = 7, Edges[][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 4}, {1, 5}, {3, 6}}, Que
8 min read
Maximum number of edges to be removed to contain exactly K connected components in the Graph
Given an undirected graph G with N nodes, M edges, and an integer K, the task is to find the maximum count of edges that can be removed such that there remains exactly K connected components after the removal of edges. If the graph cannot contain K connect components, print -1. Examples: Input: N = 4, M = 3, K = 2, Edges[][] = {{1, 2}, {2, 3}, {3,
9 min read
Smallest vertex in the connected components of all the vertices in given undirect graph
Given an undirected graph G(V, E) consisting of2 N vertices and M edges, the task is to find the smallest vertex in the connected component of the vertex i for all values of i in the range [1, N]. Examples: Input: N = 5, edges[] = {{1, 2}, {2, 3}, {4, 5}}Output: 1 1 1 4 4Explanation: The given graph can be divided into a set of two connected compon
11 min read
Count of connected components in given graph after removal of given Q vertices
Given an undirected graph g, the task is to find the number of coalitions formed in it after the removal of Q vertices and maximum vertices among all these connected components. A coalition is defined as the number of connected components left after removal of Q vertices i.e vertices being removed from the graph are not considered as part of the co
10 min read
Connected Components in an Undirected Graph
Given an undirected graph, the task is to print all the connected components line by line. Examples: Input: Consider the following graph Output:0 1 23 4Explanation: There are 2 different connected components.They are {0, 1, 2} and {3, 4}. Recommended PracticeNumber of ProvincesTry It! We have discussed algorithms for finding strongly connected comp
14 min read
Minimum and maximum number of connected components
Given array A[] of size N representing graph with N nodes. There is an undirected edge between i and A[i] for 1 <= i <= N. The Task for this problem is to find the minimum and maximum number of connected components in the given graph if it is allowed to add an edge between any two nodes from N nodes as long as each node has a degree at most 2
13 min read
Maximum sum of values of nodes among all connected components of an undirected graph
Given an undirected graph with V vertices and E edges. Every node has been assigned a given value. The task is to find the connected chain with the maximum sum of values among all the connected components in the graph. Examples: Input: V = 7, E = 4 Values = {10, 25, 5, 15, 5, 20, 0}   Output : Max Sum value = 35 Explanation: Component {1, 2} - Valu
15+ min read
Sum of the minimum elements in all connected components of an undirected graph
Given an array A of N numbers where A i represent the value of the (i+1) th node. Also given are M pair of edges where u and v represent the nodes that are connected by an edge. The task is to find the sum of the minimum element in all the connected components of the given undirected graph. If a node has no connectivity to any other node, count it
7 min read
Number of connected components of a graph ( using Disjoint Set Union )
Given an undirected graph G with vertices numbered in the range [0, N] and an array Edges[][] consisting of M edges, the task is to find the total number of connected components in the graph using Disjoint Set Union algorithm. Examples: Input: N = 4, Edges[][] = {{1, 0}, {2, 3}, {3, 4}}Output: 2Explanation: There are only 2 connected components as
7 min read
Find K vertices in the graph which are connected to at least one of remaining vertices
Given a connected graph with N vertices. The task is to select k(k must be less than or equals to n/2, not necessarily minimum) vertices from the graph such that all these selected vertices are connected to at least one of the non selected vertex. In case of multiple answers print any one of them. Examples: Input : Output : 1 Vertex 1 is connected
8 min read
Queries to find the count of connected Non-Empty Cells in a Matrix with updates
Given a boolean matrix mat[][] consisting of N rows and M columns, initially filled with 0's(empty cells), an integer K and queries Q[][] of the type {X, Y}, the task is to replace mat[X][Y] = 1(non-empty cells) and count the number of connected non-empty cells from the given matrix.Examples: Input: N = 3, M = 3, K = 4, Q[][] = {{0, 0}, {1, 1}, {1,
15+ min read
Article Tags :
Practice Tags :