Skip to content
Related Articles

Related Articles

Check for transitive property in a given Undirected Graph
  • Difficulty Level : Easy
  • Last Updated : 11 Feb, 2021

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 is connected to vertex Y, vertex Y is connected to vertex Z, then vertex X must be connected to the vertex Z.

Examples:

Input: N = 4, M = 3 Edges[] = {{1, 3}, {3, 4}, {1, 4}}
Output: YES 
Explanation:



Input : N = 4, M = 4, Edges[] = {{3, 1}, {2, 3}, {3, 4}, {1, 2}}
Output: NO 
Explanation:

Naive Approach: The simplest approach to solve the above problem is to traverse over every triplet of vertices (i, j, k) and for each such triplet, check if there is an edge between vertices j and k if i and j, and i and k are directly connected by an edge with the help of an adjacency matrix. 
Time Complexity: O(N3)
Auxiliary Space: O(N2)

Efficient Approach: The idea is to find all the connected components present in the graph. Finally, check if all the connected components of the graph are a complete graph or not. If found to be true, then print “YES”. Otherwise, print “NO”. Follow the steps below to solve the problem:

  • Represent the graph, G in the form of adjacency list.
  • Find all the connected components of the graph and check if the connected component is a complete graph or not by performing the following operations: 
    • Find total count of vertices in the current connected graph say, X.
    • If all the vertices of the connected component are not connected to X – 1 vertices, then print “NO”.
  • Finally, check if all the connected components are a complete graph or not. IF found to be true, then print “YES”.

Below is the implementation of the above approach:

C++




// C++ program of the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Stores undirected graph using
// adjacency list representation
class Graph {
 
    // Stores count of vertices
    int V;
 
    // adj[i]: Store all the nodes
    // connected to i
    list<int>* adj;
 
    // DFS fucntion
    void DFSUtil(int v, bool visited[], int id[],
                 int id_number, int& c);
 
public:
    Graph(int V);
    ~Graph();
 
    // Connect two vertices v and w
    void addEdge(int v, int w);
 
    // Check if the connected componenet
    // is a compleate graph or not
    bool connectedComponents();
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V + 1];
}
 
// Destructor
Graph::~Graph() { delete[] adj; }
 
// Function to add an undirected
// edge between two vertices
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w);
    adj[w].push_back(v);
}
 
// Function to find all the connected
// components of a graph using DFS
void Graph::DFSUtil(int v, bool visited[], int id[],
                    int id_number, int& c)
{
 
    // Mark the vertex v as visited
    visited[v] = true;
 
    // Assign an id of current
    // connected componenet
    id[v] = id_number;
 
    // Increase the count of vertices in
    // current connected componenet
    c++;
 
    // Recursively call for all the
    // vertices adjacent to this vertex
    list<int>::iterator i;
 
    // Iterate over all the adjacent
    // vertices of the current vertex
    for (i = adj[v].begin(); i != adj[v].end();
         ++i) {
 
        // If current vertex is not visited
        if (!visited[*i])
            DFSUtil(*i, visited, id,
                    id_number, c);
    }
}
 
// Function to find connnected
// componenets of the graph
bool Graph::connectedComponents()
{
 
    bool* visited = new bool[V + 1];
 
    // id[i]: Stores an unique id of connected
    // component in which vertex i exists
    int* id = new int[V + 1];
 
    // Store count of nodes in current
    // connected component
    int* component_size = new int[V + 1];
 
    // Mark all the vertices as not visited
    for (int v = 1; v <= V; v++)
        visited[v] = false;
 
    for (int v = 1; v <= V; v++) {
 
        // If vertex v is not marked
        if (visited[v] == false) {
 
            // Stores the size of a component
            // in which vertex v lies
            int c = 0;
 
            // Stores id of current
            // connected component
            int id_number = v;
 
            DFSUtil(v, visited, id,
                    id_number, c);
 
            // Stores count of vertices of
            // current component
            component_size[v] = c;
        }
        else {
 
            component_size[v]
                = component_size[id[v]];
        }
    }
 
    // Iterate over all the vertices
    for (int v = 1; v <= V; v++) {
 
        // IF connected component[v] is
        // not a compleate graph
        if (component_size[v] - 1
            != (int)adj[v].size()) {
 
            delete[] visited;
            return false;
        }
    }
 
    delete[] visited;
    return true;
}
 
// Function to check if graph is
// Edge Transitive or not
void isTransitive(int N, int M,
                  vector<vector<int> > Edge)
{
 
    // Initialize a graph
    Graph G(N);
 
    // Traverse the array Edge[]
    for (int i = 0; i < M; i++) {
        G.addEdge(Edge[i][0], Edge[i][1]);
    }
 
    // If all the connected components
    // are a compleate graph
    int f = G.connectedComponents();
    if (f == 0) {
        cout << "NO\n";
    }
    else {
        cout << "YES\n";
    }
}
 
// Driver Code
int main()
{
    // Input
    int N = 4, M = 3;
    vector<vector<int> > Edge{ { 1, 3 },
                               { 3, 4 },
                               { 1, 4 } };
    isTransitive(N, M, Edge);
 
    return 0;
}

Python3




# Python3 program of the above approach
 
# Function to add an undirected
# edge between two vertices
def addEdge(v, w):
    global adj
    adj[v].append(w)
    adj[w].append(v)
 
# Function to find all the connected
# components of a graph using DFS
def DFSUtil(v, id, id_number):
    global visited, adj, c
 
    # Mark the vertex v as visited
    visited[v] = True
 
    # Assign an id of current
    # connected componenet
    id[v] = id_number
 
    # Increase the count of vertices in
    # current connected componenet
    c += 1
 
    # Iterate over all the adjacent
    # vertices of the current vertex
    for i in adj[v]:
       
        # If current vertex is not visited
        if (not visited[i]):
            DFSUtil(i, id, id_number)
 
# Function to find connnected
# componenets of the graph
def connectedComponents():
    global V, adj, visited, c
 
    # id[i]: Stores an unique id of connected
    # component in which vertex i exists
    id = [0]*(V + 1)
 
    # Store count of nodes in current
    # connected component
    component_size = [0]*(V + 1)
    for v in range(1, V + 1):
 
        # If vertex v is not marked
        if (visited[v] == False):
 
            # Stores the size of a component
            # in which vertex v lies
            c = 0
 
            # Stores id of current
            # connected component
            id_number = v
            DFSUtil(v, id, id_number)
 
            # Stores count of vertices of
            # current component
            component_size[v] = c
        else:
 
            component_size[v] = component_size[id[v]]
 
    # Iterate over all the vertices
    for v in range(1, V + 1):
 
        # IF connected component[v] is
        # not a compleate graph
        if (component_size[v] - 1 != len(adj[v])):
            return False
    return True
 
# Function to check if graph is
# Edge Transitive or not
def isTransitive(N, M, Edge):
    global adj, visited, c
 
    # Traverse the array Edge[]
    for i in range(M):
        addEdge(Edge[i][0], Edge[i][1])
 
    # If all the connected components
    # are a compleate graph
    f = connectedComponents()
    if (f == 0):
        print("NO")
    else:
        print("YES")
 
# Driver Code
if __name__ == '__main__':
     
    # Input
    V, c = 5, 0
    adj = [[] for i in range(V + 1)]
    visited = [False] * (V + 1)
 
    N, M = 4, 3
    Edge = [ [ 1, 3 ],
           [ 3, 4 ],
           [ 1, 4 ] ]
    isTransitive(N, M, Edge)
 
    # This code is contributed by mohit kumar 29
Output: 
YES

 

Time Complexity: O(N + M)
Auxiliary Space: O(N2)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.

My Personal Notes arrow_drop_up
Recommended Articles
Page :