Open In App

Transitive Closure of a Graph using DFS

Last Updated : 18 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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:


Untitled-Diagram-(1)

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, DFS solution 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++
// C++ program to print transitive closure of a graph
#include <bits/stdc++.h>
using namespace std;

class Graph {
    int V; // No. of vertices
    bool** tc; // To store transitive closure
    list<int>* adj; // array of adjacency lists
    void DFSUtil(int u, int v);

public:
    Graph(int V); // Constructor

    // function to add an edge to graph
    void addEdge(int v, int w) { adj[v].push_back(w); }

    // prints transitive closure matrix
    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));
    }
}

// A recursive DFS traversal function that finds
// all reachable vertices for s.
void Graph::DFSUtil(int s, int v) {
    // Mark reachability from s to v as true.
    tc[s][v] = true;

    // Explore all vertices adjacent to v
    for (int u : adj[v]) {
        // If s is not yet connected to u, explore further
        if (!tc[s][u]) {
            DFSUtil(s, u);
        }
    }
}
// The function to find transitive closure. It uses
// recursive DFSUtil()
void Graph::transitiveClosure()
{
    // Call the recursive helper function to print DFS
    // traversal starting from all vertices one by one
    for (int i = 0; i < V; i++)
        DFSUtil(i,
                i); // Every vertex is reachable from self.

    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++)
            cout << tc[i][j] << " ";
        cout << endl;
    }
}

// Driver code
int main()
{

    // Create a graph given in the above diagram
    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
// JAVA program to print transitive
// closure of a graph.

import java.util.ArrayList;
import java.util.Arrays;

// A directed graph using 
// adjacency list representation
public class Graph {

        // No. of vertices in graph
    private int vertices; 

        // adjacency list
    private ArrayList<Integer>[] adjList;

        // To store transitive closure
    private int[][] tc;

    // Constructor
    public Graph(int vertices) {

             // initialise vertex count
             this.vertices = vertices; 
             this.tc = new int[this.vertices][this.vertices];

             // initialise adjacency list
             initAdjList(); 
    }

    // utility method to initialise adjacency list
    @SuppressWarnings("unchecked")
    private void initAdjList() {

        adjList = new ArrayList[vertices];
        for (int i = 0; i < vertices; i++) {
            adjList[i] = new ArrayList<>();
        }
    }

    // add edge from u to v
    public void addEdge(int u, int v) {
                 
      // Add v to u's list.
        adjList[u].add(v); 
    }

    // The function to find transitive
    // closure. It uses
    // recursive DFSUtil()
    public void transitiveClosure() {

        // Call the recursive helper
        // function to print DFS
        // traversal starting from all
        // vertices one by one
        for (int i = 0; i < vertices; i++) {
            dfsUtil(i, i);
        }

        for (int i = 0; i < vertices; i++) {
          System.out.println(Arrays.toString(tc[i]));
        }
    }

    // A recursive DFS traversal
    // function that finds
    // all reachable vertices for s
    private void dfsUtil(int s, int v) {

        // Mark reachability from 
        // s to v as true.
       if(s==v){
          tc[s][v] = 1;
       }
      else
        tc[s][v] = 1;
        
        // Find all the vertices reachable
        // through v
        for (int adj : adjList[v]) {            
            if (tc[s][adj]==0) {
                dfsUtil(s, adj);
            }
        }
    }
    
    // Driver Code
    public static void main(String[] args) {

        // Create a graph given
        // in the above diagram
        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();

    }
}


// This code is contributed
// by Himanshu Shekhar
C#
// C# program to print transitive
// closure of a graph.
using System;
using System.Collections.Generic;

// A directed graph using
// adjacency list representation
public class Graph {

    // No. of vertices in graph
    private int vertices;

    // adjacency list
    private List<int>[] adjList;

    // To store transitive closure
    private int[, ] tc;

    // Constructor
    public Graph(int vertices)
    {

        // initialise vertex count
        this.vertices = vertices;
        this.tc = new int[this.vertices, this.vertices];

        // initialise adjacency list
        initAdjList();
    }

    // utility method to initialise adjacency list
    private void initAdjList()
    {

        adjList = new List<int>[ vertices ];
        for (int i = 0; i < vertices; i++) {
            adjList[i] = new List<int>();
        }
    }

    // add edge from u to v
    public void addEdge(int u, int v)
    {

        // Add v to u's list.
        adjList[u].Add(v);
    }

    // The function to find transitive
    // closure. It uses
    // recursive DFSUtil()
    public void transitiveClosure()
    {

        // Call the recursive helper
        // function to print DFS
        // traversal starting from all
        // vertices one by one
        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();
        }
    }

    // A recursive DFS traversal
    // function that finds
    // all reachable vertices for s
    private void dfsUtil(int s, int v)
    {

        // Mark reachability from
        // s to v as true.
        tc[s, v] = 1;

        // Find all the vertices reachable
        // through v
        foreach(int adj in adjList[v])
        {
            if (tc[s, adj] == 0) {
                dfsUtil(s, adj);
            }
        }
    }

    // Driver Code
    public static void Main(String[] args)
    {

        // Create a graph given
        // in the above diagram
        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();
    }
}

// This code is contributed by Rajput-Ji
Javascript
<script>
/* Javascript program to print transitive
 closure of a graph*/
 
    class Graph
    {
        // Constructor
        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] = [];
        }

        // function to add an edge to graph
        addEdge(v, w)
        {
            this.adj[v].push(w);
        }

        // A recursive DFS traversal function that finds
        // all reachable vertices for s.
        DFSUtil(s, v)
        {
            // Mark reachability from s to v as true.
            this.tc[s][v] = 1;

            // Find all the vertices reachable through v
            for(let i of this.adj[v].values())
            {
                if(this.tc[s][i] == 0)
                    this.DFSUtil(s, i);
            }
        }

        // The function to find transitive closure. It uses
        // recursive DFSUtil()
        transitiveClosure()
        {
            // Call the recursive helper function to print DFS
            // traversal starting from all vertices one by one
            for(let i = 0; i < this.V; i++)
                this.DFSUtil(i, i); // Every vertex is reachable from self

            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 />")
            }
        }

    };

    // driver code
    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();
    
    // This code is contributed by cavi4762.
</script>
Python3
# Python program to print transitive
# closure of a graph.
from collections import defaultdict
 
class Graph:
 
    def __init__(self,vertices):
        # No. of vertices
        self.V = vertices
 
        # default dictionary to store graph
        self.graph = defaultdict(list)
 
        # To store transitive closure
        self.tc = [[0 for j in range(self.V)] for i in range(self.V)]
 
    # function to add an edge to graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
 
    # A recursive DFS traversal function that finds
    # all reachable vertices for s
    def DFSUtil(self, s, v):
 
        # Mark reachability from s to v as true.
        if(s == v):
            if( v in self.graph[s]):
              self.tc[s][v] = 1
        else:
            self.tc[s][v] = 1
 
        # Find all the vertices reachable through v
        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)
 
    # The function to find transitive closure. It uses
    # recursive DFSUtil()
    def transitiveClosure(self):
 
        # Call the recursive helper function to print DFS
        # traversal starting from all vertices one by one
        for i in range(self.V):
            self.DFSUtil(i, i)
        
        print(self.tc)
 
# Create a graph given in the above diagram
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()

Output
Transitive closure matrix is 
1 1 1 1 
1 1 1 1 
1 1 1 1 
0 0 0 1 



Time Complexity : O(V^3) where V is the number of vertexes . For dense graph, it would become O(V3) and for sparse graph, it would become O(V2).
Auxiliary Space: O(V^2) where V is number of vertices.



Previous Article
Next Article

Similar Reads

Transitive closure of a graph using Floyd Warshall Algorithm
Given a directed graph, determine if a vertex j is reachable from another vertex i for all vertex pairs (i, j) in the given graph. Here reachable means that there is a path from vertex i to j. The reach-ability matrix is called the transitive closure of a graph. For example, consider below graph Transitive closure of above graphs is 1 1 1 1 1 1 1 1
12 min read
POTD Solutions | 17 Oct’ 23 | Transitive Closure of a Graph
Welcome to the daily solutions of our PROBLEM OF THE DAY (POTD). We will discuss the entire problem step-by-step and work towards developing an optimized solution. This will not only help you brush up on your concepts of Graphs but will also help you build up problem-solving skills. POTD 17 October: Transitive closure of a GraphGiven a directed gra
11 min read
Check for transitive property in a given Undirected Graph
Given an undirected graph G with vertices numbered in the range [1, N] and an array Edges[][] consisting of M edges, the task is to check if all triplets of the undirected graph satisfies the transitive property or not. If found to be true, then print "YES". Otherwise, print "NO". Transitive property of an undirected graph states that:If vertex X i
13 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
Check if a given graph is Bipartite using DFS
Given a connected graph, check if the graph is bipartite or not. A bipartite graph is possible if the graph coloring is possible using two colors such that vertices in a set are colored with the same color. Note that it is possible to color a cycle graph with an even cycle using two colors. For example, see the following graph. It is not possible t
9 min read
Minimum number of edges between two vertices of a graph using DFS
Given an undirected graph G(V, E) with N vertices and M edges. We need to find the minimum number of edges between a given pair of vertices (u, v). We have already discussed this problem using the BFS approach, here we will use the DFS approach. Examples: Input: For the following given graph, find the minimum number of edges between vertex pair (0,
10 min read
Traverse graph in lexicographical order of nodes using DFS
Given a graph, G consisting of N nodes, a source S, and an array Edges[][2] of type {u, v} that denotes that there is an undirected edge between node u and v, the task is to traverse the graph in lexicographical order using DFS. Examples: Input: N = 10, M = 10, S = 'a', Edges[][2] = { { 'a', 'y' }, { 'a', 'z' }, { 'a', 'p' }, { 'p', 'c' }, { 'p', '
8 min read
C program to implement DFS traversal using Adjacency Matrix in a given Graph
Given a undirected graph with V vertices and E edges. The task is to perform DFS traversal of the graph. Examples: Input: V = 7, E = 7Connections: 0-1, 0-2, 1-3, 1-4, 1-5, 1-6, 6-2See the diagram for connections: Output : 0 1 3 4 5 6 2Explanation: The traversal starts from 0 and follows the following path 0-1, 1-3, 1-4, 1-5, 1-6, 6-2. Input: V = 1,
3 min read
Graph implementation using STL for competitive programming | Set 1 (DFS of Unweighted and Undirected)
We have introduced Graph basics in Graph and its representations. In this post, a different STL-based representation is used that can be helpful to quickly implement graphs using vectors. The implementation is for the adjacency list representation of the graph. Following is an example undirected and unweighted graph with 5 vertices. Below is an adj
7 min read
Check if the given permutation is a valid DFS of graph
Given a graph with N nodes numbered from 1 to N and M edges and an array of numbers from 1 to N. Check if it is possible to obtain any permutation of array by applying DFS (Depth First Traversal) on given graph. Prerequisites: DFS | Map in CPP Examples: Input: N = 3, M = 2 Edges are: 1) 1-2 2) 2-3 P = {1, 2, 3} Output: YES Explanation: Since there
12 min read
Article Tags :
Practice Tags :