Largest component size in a graph formed by connecting non-co-prime nodes


Given a graph with N nodes and their values defined in array A, the task is to find the largest component size in a graph by connecting non-co-prime nodes. An edge is between two nodes U and V if they are non-co-prime which means that the greatest common divisor of A[U] and A[V] should be greater than 1.

Examples:

Input : A = [4, 6, 15, 35]
Output : 4
Graph will be :
         4
         |
         6
         |
         15
         |
         35

Input : A = [2, 3, 6, 7, 4, 12, 21, 39]
Output : 8

Naive Approach:
We can iterate over all the pairs of nodes and check whether they are co-prime or not. If they are not co-prime we will connect them. Once the graph is created, we will apply Depth First Search to find the maximum component size.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <bits/stdc++.h>
using namespace std;
   
int dfs(int u, vector<int>* adj, int vis[])
{
    // mark this node as visited
    vis[u] = 1;
    int componentSize = 1;
   
    // apply dfs and add nodes belonging to this component
    for (auto it : adj[u]) {
        if (!vis[it]) {
            componentSize += dfs(it, adj, vis);
        }
    }
    return componentSize;
}
   
int maximumComponentSize(int a[], int n)
{
    // create graph and store in adjacency list form
    vector<int> adj[n];
   
    // iterate over all pair of nodes
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            // if not co-prime
            if (__gcd(a[i], a[j]) > 1)
                // build undirected graph
                adj[i].push_back(j);
            adj[j].push_back(i);
        }
    }
    int answer = 0;
   
    // visited array for dfs
    int vis[n];
    for(int k=0;k<n;k++){
      vis[k]=0;
    }
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            answer = max(answer, dfs(i, adj, vis));
        }
    }
    return answer;
}
   
// Driver Code
int main()
{
    int n = 8;
    int A[] = { 2, 3, 6, 7, 4, 12, 21, 39 };
    cout << maximumComponentSize(A, n);
    return 0;
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

from math import gcd
def dfs(u, adj, vis):
  
    # mark this node as visited
    vis[u] = 1
    componentSize = 1
  
    # apply dfs and add nodes belonging to this component
    for x in adj[u]:
        if (vis[x] == 0):
            componentSize += dfs(x, adj, vis)
    return componentSize
  
def maximumComponentSize(a,n):
  
    # create graph and store in adjacency list form
    adj = [[] for i in range(n)]
  
    # iterate over all pair of nodes
    for i in range(n):
        for j in range(i + 1, n):
            # if not co-prime
            if (gcd(a[i], a[j]) > 1):
                # build undirected graph
                adj[i].append(j)
            adj[j].append(i)
    answer = 0
  
    # visited array for dfs
    vis = [0 for i in range(n)]
    for i in range(n):
        if (vis[i]==False):
            answer = max(answer, dfs(i, adj, vis))
    return answer
  
# Driver Code
if __name__ == '__main__':
    n = 8
    A = [2, 3, 6, 7, 4, 12, 21, 39]
    print(maximumComponentSize(A, n))
  
# This code is contributed by Bhupendra_Singh

chevron_right


Output:



8

Time complexity : O(N2)

Efficient Approach

  • For any two numbers to be non-coprime they must have at least one common factor. So instead of traversing through all the pairs, it’s better to prime factorize each node value. The idea is to then club together numbers with common factors as a single group
  • Prime factorization can be done efficiently using Sieve of eratosthenes. For clubbing together of nodes we will use Disjoint set data structure (Union by Rank and Path Compression).
  • Following information will be stored :

    par[i] -> represents the parent of node i
    size[i] -> represents the size of the component node i belongs to
    id[p] -> represents at which node prime number p was first seen as a factor of A[i]

    For each node value, we will factorise and store the prime factors in set S. Iterate each element of S. If the prime number is seen for the first time as a factor of some number (id[p] is zero), then mark this prime’s id with the current index. If this prime has been marked, then simply merge this node with that of id[p].

    This way all nodes will belong to some component finally, and size[i] will be the size of component node i belongs to.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <bits/stdc++.h>
   
using namespace std;
   
// smallest prime factor
int spf[100005];
   
// Sieve of Eratosthenes
void sieve()
{
    for (int i = 2; i < 100005; i++) {
        // is spf[i] = 0, then it's prime
        if (spf[i] == 0) {
            spf[i] = i;
  
            for (int j = 2 * i; j < 100005; j += i) {
  
                // smallest prime factor of all multiples is i
                if (spf[j] == 0)
                    spf[j] = i;
            }
        }
    }
}
   
// Prime factorise n,
// and store prime factors in set s
void factorize(int n, set<int>& s)
{
   
    while (n > 1) {
        int z = spf[n];
        s.insert(z);
        while (n % z == 0)
            n /= z;
    }
}
   
// for implementing DSU
int id[100005];
int par[100005];
int sizeContainer[100005];
   
// root of component of node i
int root(int i)
{
    if (par[i] == i)
        return i;
    // finding root as well as applying
    // path compression
    else
        return par[i] = root(par[i]);
}
   
// merging two components
void merge(int a, int b)
{
   
    // find roots of both components
    int p = root(a);
    int q = root(b);
   
    // if already belonging to the same compenent
    if (p == q)
        return;
   
    // Union by rank, the rank in this case is
    // sizeContainer of the component. 
    // Smaller sizeContainer will be merged into
    // larger, so the larger's root will be 
    // final root
    if (sizeContainer[p] > sizeContainer[q])
        swap(p, q);
   
    par[p] = q;
    sizeContainer[q] += sizeContainer[p];
}
   
// Function to find the maximum sized container
int maximumComponentsizeContainer(int a[], int n)
{
   
    // intitalise the parents, 
    // and component sizeContainer
    for (int i = 0; i < 100005; i++) {
        // intitally all component sizeContainers are 1
        // ans each node it parent of itself
        par[i] = i;
        sizeContainer[i] = 1;
    }
   
    sieve();
   
    for (int i = 0; i < n; i++) {
        // store prime factors of a[i] in s
        set<int> s;
        factorize(a[i], s);
   
        for (auto it : s) {
            // if this prime is seen as a factor
            // for the first time
            if (id[it] == 0)
                id[it] = i + 1;
            // if not then merge with that component
            // in which this prime was previously seen
            else
                merge(i + 1, id[it]);
        }
    }
   
    int answer = 0;
  
    // maximum of sizeContainer of all components
    for (int i = 0; i < n; i++)
        answer = max(answer, sizeContainer[i]);
   
    return answer;
}
  
// Driver Code
int main()
{
    int n = 8;
    int A[] = { 2, 3, 6, 7, 4, 12, 21, 39 };
   
    cout << maximumComponentsizeContainer(A, n);
   
    return 0;
}

chevron_right


Output: 8

Time Complexity : O(N * log(max(A)))

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

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : bgangwar59