Open In App

Graph Connectivity above Threshold value

Last Updated : 25 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two integers N and K, where N denotes the number of vertices in a Graph. There is an edge between two vertices u and v if there exists some z > K: u % z ==0: v % z ==0. Now you have to answer Q queries of the form [ i, j ] where you have to print whether i and j are connected (i.e. there is some path between i and j ) or not.

Examples:

Input: N=6, K=2, queries: [[1, 4],[2, 5],[3, 6]]
Output: false false true
Explanation:
In the query [1, 4] there is no connection, between vertex 1 and vertex 4 in the graph so the result is “false.”
Likewise in the query [2, 5] there is no link between vertex 2 and vertex 5 in the graph resulting in “false” again.
However with regards to the query [3, 6] a path does exist between vertex 3 and vertex 6 in the graph leading to a result of “true.”

Input: N = 8, K = 3, queries = [[1, 5], [2, 7], [4, 8], [3, 6]]
Output: false false true false
Explanation:
In the query [1, 5] there is no path connecting vertex 1 and vertex 5 in the graph; thus it yields a result of “false.”
for the query [2,7] there is no connection between vertex 2 and vertex 7 in the graph; henceforth producing a result of “false.”
Additionally, when considering the query [4,8] there is a path linking vertex 4 and vertex 8 within the graph. As a result, “true” is returned.
However, the fourth query[3,6] reveals no path connecting vertex three and six, within this graph. Therefore the outcome will be evaluated as”false.”

Approach: To solve the problem follow the below idea:

The main idea is to utilize the Union Find (Disjoint Set Union) data structure, for creating and handling the connections in the graph. By going through values of z from K+1 to N and linking vertices that satisfy the given conditions the algorithm constructs the graph. Then for each inquiry it verifies if two vertices belong to the group by locating their root parents using path compression, in the Union Find operations.

The following steps are required to solve this problem:

  • Create a parent array of size N+1 where each vertex is initially its own parent.
  • Build the graph such that gcd(u,v) should be greater than K.
  • To satisfy given condition Iterate from K+1 to N, considering each u.
    • For each u, find vertice v that starts from 2*u to N.
    • Use the union function to connect u and v by updating their parent to the same root parent.
  • For each query [i, j]:
    • Use the find function to find the root parent of i and j.
    • If both vertices share the same root parent, they are connected; otherwise, they are not.
  • Return a list of results, indicating connectivity for each query.

Below is the implementation for the above approach:

C++




#include <iostream>
#include <vector>
 
using namespace std;
 
// Function to find the representative of a set using path compression
int find(vector<int>& parent, int i) {
    if (parent[i] == -1) {
        return i;
    }
     
    // Path compression
    parent[i] = find(parent, parent[i]);
    return parent[i];
}
 
// Function to perform union operation of two sets based on rank
void unionSets(vector<int>& parent, vector<int>& rank, int i, int j) {
    int parent_i = find(parent, i);
    int parent_j = find(parent, j);
     
    if (parent_i != parent_j) {
        if (rank[parent_i] < rank[parent_j]) {
            parent[parent_i] = parent_j;
        } else if (rank[parent_i] > rank[parent_j]) {
            parent[parent_j] = parent_i;
        } else {
            parent[parent_j] = parent_i;
            rank[parent_i]++;
        }
    }
}
 
// Function to check if two elements are connected in the graph
vector<bool> isConnected(int N, int K, vector<vector<int>>& queries) {
    vector<int> parent(N + 1, -1);
    vector<int> rank(N + 1, 0);
     
    vector<bool> results(queries.size(), false);
 
    // Build the graph using the given conditions
    for (int z = K + 1; z <= N; z++) {
        for (int u = z * 2; u <= N; u += z) {
            unionSets(parent, rank, z, u);
        }
    }
 
    // Check connectivity for each query
    for (int idx = 0; idx < queries.size(); idx++) {
        int i = queries[idx][0];
        int j = queries[idx][1];
        int parent_i = find(parent, i);
        int parent_j = find(parent, j);
         
        // Store true if connected, false otherwise
        results[idx] = (parent_i == parent_j);
    }
 
    return results;
}
 
int main() {
    // Input 1
    int N1 = 6, K1 = 2;
    vector<vector<int>> queries1 = {{1, 4}, {2, 5}, {3, 6}};
    vector<bool> output1 = isConnected(N1, K1, queries1);
     
    // Output 1
    for (bool result : output1) {
        cout << (result ? "true" : "false") << " ";
    }
    cout << endl;
 
    // Input 2
    int N2 = 8, K2 = 3;
    vector<vector<int>> queries2 = {{1, 5}, {2, 7}, {4, 8}, {3, 6}};
    vector<bool> output2 = isConnected(N2, K2, queries2);
 
    // Output 2
    for (bool result : output2) {
        cout << (result ? "true" : "false") << " ";
    }
    cout << endl;
 
    return 0;
}


Java




// Java code for the above approach
 
import java.util.*;
 
public class Main {
    // Function to find the representative of a set using
    // path compression
    private static int find(List<Integer> parent, int i)
    {
        if (parent.get(i) == -1) {
            return i;
        }
 
        // Path compression
        parent.set(i, find(parent, parent.get(i)));
        return parent.get(i);
    }
 
    // Function to perform union operation of two sets based
    // on rank
    private static void unionSets(List<Integer> parent,
                                  List<Integer> rank, int i,
                                  int j)
    {
        int parent_i = find(parent, i);
        int parent_j = find(parent, j);
 
        if (parent_i != parent_j) {
            if (rank.get(parent_i) < rank.get(parent_j)) {
                parent.set(parent_i, parent_j);
            }
            else if (rank.get(parent_i)
                     > rank.get(parent_j)) {
                parent.set(parent_j, parent_i);
            }
            else {
                parent.set(parent_j, parent_i);
                rank.set(parent_i, rank.get(parent_i) + 1);
            }
        }
    }
 
    // Function to check if two elements are connected in
    // the graph
    private static List<Boolean>
    isConnected(int N, int K, List<List<Integer> > queries)
    {
        List<Integer> parent = new ArrayList<>(
            Arrays.asList(new Integer[N + 1]));
        List<Integer> rank = new ArrayList<>(
            Arrays.asList(new Integer[N + 1]));
        for (int i = 0; i <= N; i++) {
            parent.set(i, -1);
            rank.set(i, 0);
        }
 
        List<Boolean> results
            = new ArrayList<>(queries.size());
 
        // Build the graph using the given conditions
        for (int z = K + 1; z <= N; z++) {
            for (int u = z * 2; u <= N; u += z) {
                unionSets(parent, rank, z, u);
            }
        }
 
        // Check connectivity for each query
        for (List<Integer> query : queries) {
            int i = query.get(0);
            int j = query.get(1);
            int parent_i = find(parent, i);
            int parent_j = find(parent, j);
 
            // Store true if connected, false otherwise
            results.add(parent_i == parent_j);
        }
 
        return results;
    }
 
    public static void main(String[] args)
    {
        // Input 1
        int N1 = 6, K1 = 2;
        List<List<Integer> > queries1
            = new ArrayList<>(Arrays.asList(
                new ArrayList<>(Arrays.asList(1, 4)),
                new ArrayList<>(Arrays.asList(2, 5)),
                new ArrayList<>(Arrays.asList(3, 6))));
        List<Boolean> output1
            = isConnected(N1, K1, queries1);
 
        // Output 1
        for (boolean result : output1) {
            System.out.print(result ? "true " : "false ");
        }
        System.out.println();
 
        // Input 2
        int N2 = 8, K2 = 3;
        List<List<Integer> > queries2
            = new ArrayList<>(Arrays.asList(
                new ArrayList<>(Arrays.asList(1, 5)),
                new ArrayList<>(Arrays.asList(2, 7)),
                new ArrayList<>(Arrays.asList(4, 8)),
                new ArrayList<>(Arrays.asList(3, 6))));
        List<Boolean> output2
            = isConnected(N2, K2, queries2);
 
        // Output 2
        for (boolean result : output2) {
            System.out.print(result ? "true " : "false ");
        }
        System.out.println();
    }
}
 
// This code is contributed by Abhinav Mahajan (abhinav_m22)


Python




# Function to find the representative of
# a set using path compression
 
 
def find(parent, i):
    if parent[i] == -1:
        return i
 
      # Path compression
    parent[i] = find(parent, parent[i])
    return parent[i]
 
# Function to perform union operation of
# two sets based on rank
 
 
def union(parent, rank, i, j):
    parent_i = find(parent, i)
    parent_j = find(parent, j)
    if parent_i != parent_j:
        if rank[parent_i] < rank[parent_j]:
            parent[parent_i] = parent_j
        elif rank[parent_i] > rank[parent_j]:
            parent[parent_j] = parent_i
        else:
            parent[parent_j] = parent_i
            rank[parent_i] += 1
 
# Function to check if two elements are connected in the graph
 
 
def is_connected(N, K, queries):
 
    # Initialize parent and rank arrays for
    # disjoint-set data structure
    parent = [-1] * (N + 1)
    rank = [0] * (N + 1)
 
    # Initialize results list to store query results
    results = [False] * len(queries)
 
    # Build the graph using the given conditions
    for z in range(K + 1, N + 1):
        for u in range(z * 2, N + 1, z):
            union(parent, rank, z, u)
 
    # Check connectivity for each query
    for idx, query in enumerate(queries):
        i, j = query
        parent_i = find(parent, i)
        parent_j = find(parent, j)
        # Store True if connected, False otherwise
        results[idx] = (parent_i == parent_j)
 
    return results
 
 
# Input 1
N1, K1 = 6, 2
queries1 = [[1, 4], [2, 5], [3, 6]]
output1 = is_connected(N1, K1, queries1)
print(output1)
 
# Input 2
N2, K2 = 8, 3
queries2 = [[1, 5], [2, 7], [4, 8], [3, 6]]
output2 = is_connected(N2, K2, queries2)
print(output2)


C#




using System;
using System.Collections.Generic;
 
class DisjointSet
{
    // Function to find the representative of a set using path compression
    private static int Find(List<int> parent, int i)
    {
        if (parent[i] == -1)
        {
            return i;
        }
 
        // Path compression
        parent[i] = Find(parent, parent[i]);
        return parent[i];
    }
 
    // Function to perform union operation of two sets based on rank
    private static void UnionSets(List<int> parent, List<int> rank, int i, int j)
    {
        int parent_i = Find(parent, i);
        int parent_j = Find(parent, j);
 
        if (parent_i != parent_j)
        {
            if (rank[parent_i] < rank[parent_j])
            {
                parent[parent_i] = parent_j;
            }
            else if (rank[parent_i] > rank[parent_j])
            {
                parent[parent_j] = parent_i;
            }
            else
            {
                parent[parent_j] = parent_i;
                rank[parent_i]++;
            }
        }
    }
 
    // Function to check if two elements are connected in the graph
    private static List<bool> IsConnected(int N, int K, List<List<int>> queries)
    {
        List<int> parent = new List<int>(new int[N + 1]);
        List<int> rank = new List<int>(new int[N + 1]);
        List<bool> results = new List<bool>(queries.Count);
 
        // Initialize parent and rank arrays
        for (int i = 0; i <= N; i++)
        {
            parent[i] = -1;
            rank[i] = 0;
        }
 
        // Build the graph using the given conditions
        for (int z = K + 1; z <= N; z++)
        {
            for (int u = z * 2; u <= N; u += z)
            {
                UnionSets(parent, rank, z, u);
            }
        }
 
        // Check connectivity for each query
        foreach (List<int> query in queries)
        {
            int i = query[0];
            int j = query[1];
            int parent_i = Find(parent, i);
            int parent_j = Find(parent, j);
 
            // Store true if connected, false otherwise
            results.Add(parent_i == parent_j);
        }
 
        return results;
    }
 
    static void Main()
    {
        // Input 1
        int N1 = 6, K1 = 2;
        List<List<int>> queries1 = new List<List<int>> { new List<int> { 1, 4 }, new List<int> { 2, 5 }, new List<int> { 3, 6 } };
        List<bool> output1 = IsConnected(N1, K1, queries1);
 
        // Output 1
        Console.WriteLine(string.Join(" ", output1));
 
        // Input 2
        int N2 = 8, K2 = 3;
        List<List<int>> queries2 = new List<List<int>> { new List<int> { 1, 5 }, new List<int> { 2, 7 }, new List<int> { 4, 8 }, new List<int> { 3, 6 } };
        List<bool> output2 = IsConnected(N2, K2, queries2);
 
        // Output 2
        Console.WriteLine(string.Join(" ", output2));
    }
}


Javascript




// Function to find the representative of a set using path compression
function find(parent, i) {
    if (parent[i] === -1) {
        return i;
    }
 
    // Path compression
    parent[i] = find(parent, parent[i]);
    return parent[i];
}
 
// Function to perform union operation of two sets based on rank
function unionSets(parent, rank, i, j) {
    const parent_i = find(parent, i);
    const parent_j = find(parent, j);
 
    if (parent_i !== parent_j) {
        if (rank[parent_i] < rank[parent_j]) {
            parent[parent_i] = parent_j;
        } else if (rank[parent_i] > rank[parent_j]) {
            parent[parent_j] = parent_i;
        } else {
            parent[parent_j] = parent_i;
            rank[parent_i]++;
        }
    }
}
 
// Function to check if two elements are connected in the graph
function isConnected(N, K, queries) {
    const parent = new Array(N + 1).fill(-1);
    const rank = new Array(N + 1).fill(0);
 
    const results = new Array(queries.length).fill(false);
 
    // Build the graph using the given conditions
    for (let z = K + 1; z <= N; z++) {
        for (let u = z * 2; u <= N; u += z) {
            unionSets(parent, rank, z, u);
        }
    }
 
    // Check connectivity for each query
    for (let idx = 0; idx < queries.length; idx++) {
        const i = queries[idx][0];
        const j = queries[idx][1];
        const parent_i = find(parent, i);
        const parent_j = find(parent, j);
 
        // Store true if connected, false otherwise
        results[idx] = parent_i === parent_j;
    }
 
    return results;
}
 
// Input 1
const N1 = 6;
const K1 = 2;
const queries1 = [[1, 4], [2, 5], [3, 6]];
const output1 = isConnected(N1, K1, queries1);
 
// Output 1
console.log(output1.map(result => result ? "true" : "false").join(" "));
 
// Input 2
const N2 = 8;
const K2 = 3;
const queries2 = [[1, 5], [2, 7], [4, 8], [3, 6]];
const output2 = isConnected(N2, K2, queries2);
 
// Output 2
console.log(output2.map(result => result ? "true" : "false").join(" "));


Output

false false true 
false false true false 








Time Complexity: O(N + Q) where N is the number of elements, and Q is the number of queries.
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads