Given a directed graph, find out if a vertex v is reachable from another vertex u for all vertex pairs (u, v) in the given graph. Here reachable means that there is a path from vertex u to v. The reach-ability matrix is called transitive closure of a graph.
For example, consider below graph
Transitive closure of above graphs is
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 1
We have discussed an O(V3) solution for this here. The solution was based on Floyd Warshall Algorithm. In this post, an O(V(V+E)) algorithm for the same is discussed. So for dense graph, it would become O(V3) and for sparse graph, it would become O(V2).
Below are the abstract steps of the algorithm.
- Create a matrix tc[V][V] that would finally have transitive closure of the given graph. Initialize all entries of tc[][] as 0.
- Call DFS for every node of the graph to mark reachable vertices in tc[][]. In recursive calls to DFS, we don’t call DFS for an adjacent vertex if it is already marked as reachable in tc[][].
Below is the implementation of the above idea. The code uses adjacency list representation of input graph and builds a matrix tc[V][V] such that tc[u][v] would be true if v is reachable from u.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
class Graph {
int V;
bool ** tc;
list< int >* adj;
void DFSUtil( int u, int v);
public :
Graph( int V);
void addEdge( int v, int w) { adj[v].push_back(w); }
void transitiveClosure();
};
Graph::Graph( int V)
{
this ->V = V;
adj = new list< int >[V];
tc = new bool *[V];
for ( int i = 0; i < V; i++) {
tc[i] = new bool [V];
memset (tc[i], false , V * sizeof ( bool ));
}
}
void Graph::DFSUtil( int s, int v)
{
if (s == v) {
tc[s][v] = true ;
}
else
tc[s][v] = true ;
list< int >::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i) {
if (tc[s][*i] == false ) {
if (*i == s) {
tc[s][*i] = 1;
}
else {
DFSUtil(s, *i);
}
}
}
}
void Graph::transitiveClosure()
{
for ( int i = 0; i < V; i++)
DFSUtil(i,
i);
for ( int i = 0; i < V; i++) {
for ( int j = 0; j < V; j++)
cout << tc[i][j] << " " ;
cout << endl;
}
}
int main()
{
Graph g(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
cout << "Transitive closure matrix is \n" ;
g.transitiveClosure();
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Arrays;
public class Graph {
private int vertices;
private ArrayList<Integer>[] adjList;
private int [][] tc;
public Graph( int vertices) {
this .vertices = vertices;
this .tc = new int [ this .vertices][ this .vertices];
initAdjList();
}
@SuppressWarnings ( "unchecked" )
private void initAdjList() {
adjList = new ArrayList[vertices];
for ( int i = 0 ; i < vertices; i++) {
adjList[i] = new ArrayList<>();
}
}
public void addEdge( int u, int v) {
adjList[u].add(v);
}
public void transitiveClosure() {
for ( int i = 0 ; i < vertices; i++) {
dfsUtil(i, i);
}
for ( int i = 0 ; i < vertices; i++) {
System.out.println(Arrays.toString(tc[i]));
}
}
private void dfsUtil( int s, int v) {
if (s==v){
tc[s][v] = 1 ;
}
else
tc[s][v] = 1 ;
for ( int adj : adjList[v]) {
if (tc[s][adj]== 0 ) {
dfsUtil(s, adj);
}
}
}
public static void main(String[] args) {
Graph g = new Graph( 4 );
g.addEdge( 0 , 1 );
g.addEdge( 0 , 2 );
g.addEdge( 1 , 2 );
g.addEdge( 2 , 0 );
g.addEdge( 2 , 3 );
g.addEdge( 3 , 3 );
System.out.println( "Transitive closure " +
"matrix is" );
g.transitiveClosure();
}
}
|
Python3
from collections import defaultdict
class Graph:
def __init__( self ,vertices):
self .V = vertices
self .graph = defaultdict( list )
self .tc = [[ 0 for j in range ( self .V)] for i in range ( self .V)]
def addEdge( self , u, v):
self .graph[u].append(v)
def DFSUtil( self , s, v):
if (s = = v):
if ( v in self .graph[s]):
self .tc[s][v] = 1
else :
self .tc[s][v] = 1
for i in self .graph[v]:
if self .tc[s][i] = = 0 :
if s = = i:
self .tc[s][i] = 1
else :
self .DFSUtil(s, i)
def transitiveClosure( self ):
for i in range ( self .V):
self .DFSUtil(i, i)
print ( self .tc)
g = Graph( 4 )
g.addEdge( 0 , 1 )
g.addEdge( 0 , 2 )
g.addEdge( 1 , 2 )
g.addEdge( 2 , 0 )
g.addEdge( 2 , 3 )
g.addEdge( 3 , 3 )
g.transitiveClosure()
|
C#
using System;
using System.Collections.Generic;
public class Graph {
private int vertices;
private List< int >[] adjList;
private int [, ] tc;
public Graph( int vertices)
{
this .vertices = vertices;
this .tc = new int [ this .vertices, this .vertices];
initAdjList();
}
private void initAdjList()
{
adjList = new List< int >[ vertices ];
for ( int i = 0; i < vertices; i++) {
adjList[i] = new List< int >();
}
}
public void addEdge( int u, int v)
{
adjList[u].Add(v);
}
public void transitiveClosure()
{
for ( int i = 0; i < vertices; i++) {
dfsUtil(i, i);
}
for ( int i = 0; i < vertices; i++) {
for ( int j = 0; j < vertices; j++)
Console.Write(tc[i, j] + " " );
Console.WriteLine();
}
}
private void dfsUtil( int s, int v)
{
tc[s, v] = 1;
foreach ( int adj in adjList[v])
{
if (tc[s, adj] == 0) {
dfsUtil(s, adj);
}
}
}
public static void Main(String[] args)
{
Graph g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
Console.WriteLine( "Transitive closure "
+ "matrix is" );
g.transitiveClosure();
}
}
|
Javascript
<script>
class Graph
{
constructor(v)
{
this .V = v;
this .adj = new Array(v);
this .tc = Array.from(Array(v), () => new Array(v).fill(0));
for (let i = 0; i < v; i++)
this .adj[i] = [];
}
addEdge(v, w)
{
this .adj[v].push(w);
}
DFSUtil(s, v)
{
this .tc[s][v] = 1;
for (let i of this .adj[v].values())
{
if ( this .tc[s][i] == 0)
this .DFSUtil(s, i);
}
}
transitiveClosure()
{
for (let i = 0; i < this .V; i++)
this .DFSUtil(i, i);
document.write( "Transitive closure matrix is<br />" )
for (let i=0; i < this .V; i++)
{
for (let j=0; j < this .V; j++)
document.write( this .tc[i][j] + " " );
document.write( "<br />" )
}
}
};
g = new Graph(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
g.transitiveClosure();
</script>
|
OutputTransitive closure matrix is
1 1 1 1
1 1 1 1
1 1 1 1
0 0 0 1
Time Complexity : O(V^2) where V is the number of vertexes .
Space complexity : O(V^2) where V is number of vertices.