Open In App

Check for transitive property in a given Undirected Graph

Improve
Improve
Like Article
Like
Save
Share
Report

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 function
    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 component
    // is a complete 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 component
    id[v] = id_number;
 
    // Increase the count of vertices in
    // current connected component
    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 connected
// components 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 complete 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 complete 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;
}


Java




// Java program of the above approach
 
import java.util.*;
 
class Graph {
    // Stores count of vertices
    int V;
 
    // adj[i]: Store all the nodes
    // connected to i
    ArrayList<Integer>[] adj;
 
    // DFS function
    void DFSUtil(int v, boolean[] visited, int[] id,
                 int id_number, int[] component_size)
    {
 
        // Mark the vertex v as visited
        visited[v] = true;
 
        // Assign an id of current
        // connected component
        id[v] = id_number;
 
        // Increase the count of vertices in
        // current connected component
        component_size[id_number]++;
 
        // Recursively call for all the
        // vertices adjacent to this vertex
        for (Integer i : adj[v]) {
 
            // If current vertex is not visited
            if (!visited[i])
                DFSUtil(i, visited, id, id_number,
                        component_size);
        }
    }
 
    // Function to find connected
    // components of the graph
    boolean connectedComponents()
    {
 
        boolean[] visited = new boolean[V + 1];
        int[] id = new int[V + 1];
        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]) {
 
                int id_number = v;
 
                DFSUtil(v, visited, id, id_number,
                        component_size);
            }
        }
 
        // Iterate over all the vertices
        for (int v = 1; v <= V; v++) {
 
            // IF connected component[v] is
            // not a complete graph
            if (component_size[id[v]] - 1
                != adj[v].size()) {
 
                return false;
            }
        }
 
        return true;
    }
 
    // Function to initialize graph
    Graph(int V)
    {
        this.V = V;
        adj = (ArrayList<Integer>[]) new ArrayList[V + 1];
        for (int i = 0; i <= V; i++) {
            adj[i] = new ArrayList<>();
        }
    }
 
    // Function to connect two vertices v and w
    void addEdge(int v, int w)
    {
        adj[v].add(w);
        adj[w].add(v);
    }
}
 
class Main {
    // Function to check if graph is
    // Edge Transitive or not
    static void isTransitive(int N, int M, int[][] Edge)
    {
 
        // Initialize a graph
        Graph G = new Graph(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 complete graph
        if (G.connectedComponents()) {
            System.out.println("YES");
        }
        else {
            System.out.println("NO");
        }
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int N = 4, M = 3;
        int[][] Edge = { { 1, 3 }, { 3, 4 }, { 1, 4 } };
        isTransitive(N, M, Edge);
    }
}


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 component
    id[v] = id_number
 
    # Increase the count of vertices in
    # current connected component
    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 connected
# components 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 complete 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 complete 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


C#




using System;
using System.Collections.Generic;
 
public class Graph {
    // Stores count of vertices
    public int V;
 
    // adj[i]: Store all the nodes
    // connected to i
    public List<int>[] adj;
 
    // DFS function
    public void DFSUtil(int v, bool[] visited, int[] id,
                        int id_number, int[] component_size)
    {
        // Mark the vertex v as visited
        visited[v] = true;
 
        // Assign an id of current
        // connected component
        id[v] = id_number;
 
        // Increase the count of vertices in
        // current connected component
        component_size[id_number]++;
 
        // Recursively call for all the
        // vertices adjacent to this vertex
        foreach(int i in adj[v])
        {
            // If current vertex is not visited
            if (!visited[i]) {
                DFSUtil(i, visited, id, id_number,
                        component_size);
            }
        }
    }
 
    // Function to find connected
    // components of the graph
    public bool connectedComponents()
    {
        bool[] visited = new bool[V + 1];
        int[] id = new int[V + 1];
        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]) {
                int id_number = v;
                DFSUtil(v, visited, id, id_number,
                        component_size);
            }
        }
 
        // Iterate over all the vertices
        for (int v = 1; v <= V; v++) {
            // IF connected component[v] is
            // not a complete graph
            if (component_size[id[v]] - 1 != adj[v].Count) {
                return false;
            }
        }
 
        return true;
    }
 
    // Function to initialize graph
    public Graph(int V)
    {
        this.V = V;
        adj = new List<int>[ V + 1 ];
        for (int i = 0; i <= V; i++) {
            adj[i] = new List<int>();
        }
    }
 
    // Function to connect two vertices v and w
    public void addEdge(int v, int w)
    {
        adj[v].Add(w);
        adj[w].Add(v);
    }
}
 
public class Program {
    // Function to check if graph is
    // Edge Transitive or not
    static void isTransitive(int N, int M, int[][] Edge)
    {
        // Initialize a graph
        Graph G = new Graph(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 complete graph
        if (G.connectedComponents()) {
            Console.WriteLine("YES");
        }
        else {
            Console.WriteLine("NO");
        }
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        int N = 4, M = 3;
        int[][] Edge = new int[3][];
        Edge[0] = new int[] { 1, 3 };
        Edge[1] = new int[] { 3, 4 };
        Edge[2] = new int[] { 1, 4 };
        isTransitive(N, M, Edge);
    }
}


Javascript




// JavaScript program of the above approach
 
class Graph {
    // Stores count of vertices
    constructor(V) {
        this.V = V;
        this.adj = new Array(V + 1).fill().map(() => []);
    }
    // DFS function
    DFSUtil(v, visited, id, id_number, component_size) {
     
        // Mark the vertex v as visited
        visited[v] = true;
     
        // Assign an id of current
        // connected component
        id[v] = id_number;
     
        // Increase the count of vertices in
        // current connected component
        component_size[id_number]++;
     
        // Recursively call for all the
        // vertices adjacent to this vertex
        for (let i of this.adj[v]) {
     
            // If current vertex is not visited
            if (!visited[i])
                this.DFSUtil(i, visited, id, id_number, component_size);
        }
    }
     
    // Function to find connected
    // components of the graph
    connectedComponents() {
     
        const visited = new Array(this.V + 1).fill(false);
        const id = new Array(this.V + 1).fill(0);
        const component_size = new Array(this.V + 1).fill(0);
     
        // Mark all the vertices as not visited
        for (let v = 1; v <= this.V; v++)
            visited[v] = false;
     
        for (let v = 1; v <= this.V; v++) {
     
            // If vertex v is not marked
            if (!visited[v]) {
     
                const id_number = v;
     
                this.DFSUtil(v, visited, id, id_number, component_size);
            }
        }
     
        // Iterate over all the vertices
        for (let v = 1; v <= this.V; v++) {
     
            // IF connected component[v] is
            // not a complete graph
            if (component_size[id[v]] - 1 !== this.adj[v].length) {
     
                return false;
            }
        }
     
        return true;
    }
     
    // Function to connect two vertices v and w
    addEdge(v, w) {
        this.adj[v].push(w);
        this.adj[w].push(v);
    }
 
}
 
// Function to check if graph is
// Edge Transitive or not
function isTransitive(N, M, Edge) {
    // Initialize a graph
    const G = new Graph(N);
     
    // Traverse the array Edge[]
    for (let i = 0; i < M; i++) {
        G.addEdge(Edge[i][0], Edge[i][1]);
    }
     
    // If all the connected components
    // are a complete graph
    if (G.connectedComponents()) {
        console.log("YES");
    }
    else {
        console.log("NO");
    }
 
}
 
const N = 4, M = 3;
const Edge = [[1, 3], [3, 4], [1, 4]];
isTransitive(N, M, Edge);
 
// This code is contributed by sankar.


Output: 

YES

 

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



Last Updated : 27 Feb, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads