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.
Example:
Input: adj[][] = [[1], [2], [3, 4], [0], [2]]
Output: Yes Explanation: Every node is reachable from every other node in the component.
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, then the given undirected graph is connected. This approach won't work for a directed graph. For example, consider the following graph which is not strongly connected. If we start DFS (or BFS) from vertex 0, we can reach all vertices, but if we start from any other vertex, we cannot reach all vertices.
How to do for directed graph?
A simple idea is to use a all pair shortest path algorithm like Floyd Warshall or find Transitive Closure of graph. Time complexity of this method would be O(v3). We can also do DFS V times starting from every vertex. If any DFS, doesn't visit all vertices, then graph is not strongly connected. This algorithm takes O(V*(V+E)) time which can be same as transitive closure for a dense graph.
A better idea can be Strongly Connected Components (SCC) algorithm. We can find all SCCs in O(V+E) time. If number of SCCs is one, then graph is strongly connected. The algorithm for SCC does extra work as it finds all SCCs.
Following is Kosaraju's DFS based simple algorithm that does two DFS traversals of graph:
Initialize all vertices as not visited.
Do a DFS traversal of graph starting from any arbitrary vertex v. If DFS traversal doesn't visit all vertices, then return false.
Reverse all arcs (or find transpose or reverse of graph)
Mark all vertices as not-visited in reversed graph.
Do a DFS traversal of reversed graph starting from same vertex v (Same as step 2). If DFS traversal doesn't visit all vertices, then return false. Otherwise return true.
The idea is, if every node can be reached from a vertex v, and every node can reach v, then the graph is strongly connected. In step 2, we check if all vertices are reachable from v. In step 4, we check if all vertices can reach v (In reversed graph, if all vertices are reachable from v, then all vertices can reach v in original graph). Following is the implementation of above algorithm. Implementation:
C++
#include<iostream>#include<vector>usingnamespacestd;// A recursive DFS based function// This DFS marks all vertices reachable from vertex vvoiddfsUtil(intv,vector<vector<int>>&adj,vector<bool>&visited){// Mark the current vertex as visitedvisited[v]=true;// Visit all unvisited vertices reachable from vfor(intu:adj[v]){if(!visited[u]){dfsUtil(u,adj,visited);}}}// Function that returns transpose of the graph// Transpose graph is obtained by reversing all edgesvector<vector<int>>getTranspose(vector<vector<int>>&adj){intn=adj.size();vector<vector<int>>transpose(n);// Reverse direction of every edge u -> v to v -> ufor(intv=0;v<n;v++){for(intu:adj[v]){transpose[u].push_back(v);}}returntranspose;}// Function that returns true if graph// is strongly connected, otherwise falseboolisStronglyConnected(vector<vector<int>>&adj){intn=adj.size();vector<bool>visited(n,false);// Run DFS from vertex 0 in the original graphdfsUtil(0,adj,visited);// If some vertex is not reachable, graph is not strongly connectedfor(inti=0;i<n;i++){if(!visited[i]){returnfalse;}}// Get the transpose of the graphvector<vector<int>>revAdj=getTranspose(adj);// Reset visited array for second DFSfill(visited.begin(),visited.end(),false);// Run DFS from vertex 0 in the transposed graphdfsUtil(0,revAdj,visited);// If some vertex is not reachable in transpose, graph is not strongly connectedfor(inti=0;i<n;i++){if(!visited[i]){returnfalse;}}returntrue;}intmain(){vector<vector<int>>g1(5);g1[0].push_back(1);g1[1].push_back(2);g1[2].push_back(3);g1[3].push_back(0);g1[2].push_back(4);g1[4].push_back(2);isStronglyConnected(g1)?cout<<"Yes\n":cout<<"No\n";vector<vector<int>>g2(4);g2[0].push_back(1);g2[1].push_back(2);g2[2].push_back(3);isStronglyConnected(g2)?cout<<"Yes\n":cout<<"No\n";return0;}
Java
importjava.util.ArrayList;importjava.util.Arrays;classGFG{// A recursive DFS based function// This DFS marks all vertices reachable from vertex vstaticvoiddfsUtil(intv,int[][]adj,boolean[]visited){// Mark the current vertex as visitedvisited[v]=true;// Visit all unvisited vertices reachable from vfor(intu:adj[v]){if(!visited[u]){dfsUtil(u,adj,visited);}}}// Function that returns transpose of the graph// Transpose graph is obtained by reversing all edgesstaticint[][]getTranspose(int[][]adj){intn=adj.length;ArrayList<ArrayList<Integer>>temp=newArrayList<>();for(inti=0;i<n;i++){temp.add(newArrayList<>());}// Reverse direction of every edge u -> v to v -> ufor(intv=0;v<n;v++){for(intu:adj[v]){temp.get(u).add(v);}}int[][]transpose=newint[n][];for(inti=0;i<n;i++){transpose[i]=temp.get(i).stream().mapToInt(x->x).toArray();}returntranspose;}// Function that returns true if graph// is strongly connected, otherwise falsestaticbooleanisStronglyConnected(int[][]adj){intn=adj.length;boolean[]visited=newboolean[n];// Run DFS from vertex 0 in the original graphdfsUtil(0,adj,visited);// If some vertex is not reachable, graph is not strongly connectedfor(booleanv:visited){if(!v){returnfalse;}}// Get the transpose of the graphint[][]revAdj=getTranspose(adj);// Reset visited array for second DFSArrays.fill(visited,false);// Run DFS from vertex 0 in the transposed graphdfsUtil(0,revAdj,visited);// If some vertex is not reachable in transpose, graph is not strongly connectedfor(booleanv:visited){if(!v){returnfalse;}}returntrue;}publicstaticvoidmain(String[]args){int[][]g1={{1},{2},{3,4},{0},{2}};System.out.println(isStronglyConnected(g1)?"Yes":"No");int[][]g2={{1},{2},{3},{}};System.out.println(isStronglyConnected(g2)?"Yes":"No");}}
Python
# A recursive DFS based function# This DFS marks all vertices reachable from vertex vdefdfsUtil(v,adj,visited):# Mark the current vertex as visitedvisited[v]=True# Visit all unvisited vertices reachable from vforuinadj[v]:ifnotvisited[u]:dfsUtil(u,adj,visited)# Function that returns transpose of the graph# Transpose graph is obtained by reversing all edgesdefgetTranspose(adj):n=len(adj)transpose=[[]for_inrange(n)]# Reverse direction of every edge u -> v to v -> uforvinrange(n):foruinadj[v]:transpose[u].append(v)returntranspose# Function that returns true if graph# is strongly connected, otherwise falsedefisStronglyConnected(adj):n=len(adj)visited=[False]*n# Run DFS from vertex 0 in the original graphdfsUtil(0,adj,visited)# If some vertex is not reachable, graph is not strongly connectedifnotall(visited):returnFalse# Get the transpose of the graphrevAdj=getTranspose(adj)# Reset visited array for second DFSvisited=[False]*n# Run DFS from vertex 0 in the transposed graphdfsUtil(0,revAdj,visited)# If some vertex is not reachable in transpose, graph is not strongly connectedifnotall(visited):returnFalsereturnTrueif__name__=="__main__":g1=[[1],[2],[3,4],[0],[2]]print("Yes"ifisStronglyConnected(g1)else"No")g2=[[1],[2],[3],[]]print("Yes"ifisStronglyConnected(g2)else"No")
C#
usingSystem;usingSystem.Collections.Generic;classGFG{// A recursive DFS based function// This DFS marks all vertices reachable from vertex vstaticvoiddfsUtil(intv,List<List<int>>adj,bool[]visited){// Mark the current vertex as visitedvisited[v]=true;// Visit all unvisited vertices reachable from vforeach(intuinadj[v]){if(!visited[u]){dfsUtil(u,adj,visited);}}}// Function that returns transpose of the graph// Transpose graph is obtained by reversing all edgesstaticList<List<int>>getTranspose(List<List<int>>adj){intn=adj.Count;vartranspose=newList<List<int>>();for(inti=0;i<n;i++){transpose.Add(newList<int>());}// Reverse direction of every edge u -> v to v -> ufor(intv=0;v<n;v++){foreach(intuinadj[v]){transpose[u].Add(v);}}returntranspose;}// Function that returns true if graph// is strongly connected, otherwise falsestaticboolisStronglyConnected(List<List<int>>adj){intn=adj.Count;bool[]visited=newbool[n];// Run DFS from vertex 0 in the original graphdfsUtil(0,adj,visited);// If some vertex is not reachable, graph is not strongly connectedforeach(boolvinvisited){if(!v){returnfalse;}}// Get the transpose of the graphvarrevAdj=getTranspose(adj);// Reset visited array for second DFSArray.Fill(visited,false);// Run DFS from vertex 0 in the transposed graphdfsUtil(0,revAdj,visited);// If some vertex is not reachable in transpose, graph is not strongly connectedforeach(boolvinvisited){if(!v){returnfalse;}}returntrue;}staticvoidMain(){varg1=newList<List<int>>{newList<int>{1},newList<int>{2},newList<int>{3,4},newList<int>{0},newList<int>{2}};Console.WriteLine(isStronglyConnected(g1)?"Yes":"No");varg2=newList<List<int>>{newList<int>{1},newList<int>{2},newList<int>{3},newList<int>()};Console.WriteLine(isStronglyConnected(g2)?"Yes":"No");}}
JavaScript
// A recursive DFS based function// This DFS marks all vertices reachable from vertex vfunctiondfsUtil(v,adj,visited){// Mark the current vertex as visitedvisited[v]=true;// Visit all unvisited vertices reachable from vfor(letuofadj[v]){if(!visited[u]){dfsUtil(u,adj,visited);}}}// Function that returns transpose of the graph// Transpose graph is obtained by reversing all edgesfunctiongetTranspose(adj){letn=adj.length;lettranspose=Array.from({length:n},()=>[]);// Reverse direction of every edge u -> v to v -> ufor(letv=0;v<n;v++){for(letuofadj[v]){transpose[u].push(v);}}returntranspose;}// Function that returns true if graph// is strongly connected, otherwise falsefunctionisStronglyConnected(adj){letn=adj.length;letvisited=Array(n).fill(false);// Run DFS from vertex 0 in the original graphdfsUtil(0,adj,visited);// If some vertex is not reachable, graph is not strongly connectedif(visited.includes(false)){returnfalse;}// Get the transpose of the graphletrevAdj=getTranspose(adj);// Reset visited array for second DFSvisited.fill(false);// Run DFS from vertex 0 in the transposed graphdfsUtil(0,revAdj,visited);// If some vertex is not reachable in transpose, graph is not strongly connectedif(visited.includes(false)){returnfalse;}returntrue;}// Driver Codeletg1=[[1],[2],[3,4],[0],[2]];console.log(isStronglyConnected(g1)?"Yes":"No");letg2=[[1],[2],[3],[]];console.log(isStronglyConnected(g2)?"Yes":"No");
Output
Yes
No
Time Complexity: Time complexity of above implementation is same as Depth First Search which is O(V+E) if the graph is represented using adjacency list representation.