Open In App

Construct MST from GCD

Last Updated : 09 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] of N integers. and an integer K. Construct a weighted undirected graph of N vertices numbered from 0 to N-1. An edge between the vertices i and j (j>i) is added if any one of the following conditions is satisfied:

  1. If j = i + 1, add an edge of weight K between vertices i and j.
  2. If min(ai , ai+1 ,….., aj) = gcd(ai , ai+1 ,….., aj), add an edge of weight min(ai , ai+1 ,….., aj) between vertices i and j.

The task is to determine the MST(Minimum Spanning Tree) of the resultant graph.

Examples:

Input: N=4, K=5, arr = [3, 2, 6, 3]
Output: 10
Explanation: The image shows that the cost of MST is 5 + 2 + 3 = 10

MST_1

Input: N=4, K=3, arr = [5, 10, 2, 3]
Output: 8
Explanation: The image shows that the cost of MST is 3 + 2 + 3 = 8

MST_2

Approach: The problem can be solved using the following approach:

The idea is to consider the edges which have a smaller weight first. This can be done by storing array along with its index and then sort it according to the value. For any element with index idx, we will have to move left and right separately. If we add a new element with index j while moving left or right, the condition gcd(curr_gcd, a[j]) = a[idx] should be satisfied. If it is satisfied, we can add an edge of weight a[idx] between vertices idx and j. If idx and j are already in same Connected Component then no edge will be added and we will simply break and repeat the process for remaining elements.

Follow the steps to solve the above problem:

  • Create a vector of pairs vp where each pair consists of the array element and its index and sort this vector vp in ascending order based on the array values.
  • Initialize total weight of the Minimum Spanning Tree (MST) as ans = 0.
  • Iterate through sorted elements:
    • Get the index of the current element as idx, set j to idx+1 and curr_gcd to a[idx].
    • While j is less than the size of the array:
      • Update the curr_gcd to gcd(curr_gcd, a[j]).
      • If curr_gcd is equal to a[idx] then, check whether vertices idx and j are in same connected component (this can be done using Disjoint Set Union). If they are not in same component add the edge weight (a[idx]) to the total ans and increment j, or else break.
    • Repeat the similar logic for j=idx-1.
  • Iterate through i=0 to n-1,
    • If vertices i and i+1 are not in same component add the edge weight k to the total ans.
  • Return ans.

Below is the implementation of above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
// Rank array for disjoint-set union
vector<int> rnk(200001);
 
// Parent array for disjoint-set union
vector<int> parent(200001);
 
// Function to create a new set with element 'v'
void make_set(int v)
{
    // Each element is initially its own parent
    parent[v] = v;
 
    // Initialize the rank to 0 (used in union)
    rnk[v] = 0;
}
 
// Function to find the representative (parent) of a set
// containing 'v'
int find_par(int v)
{
    if (v == parent[v])
        return v;
 
    // Path compression for optimization
    return parent[v] = find_par(parent[v]);
}
 
// Function to union two sets with elements 'a' and 'b'
void union_sets(int a, int b)
{
    a = find_par(a);
    b = find_par(b);
    if (a != b) {
        if (rnk[a] < rnk[b])
            swap(a, b);
        parent[b] = a;
        if (rnk[a] == rnk[b])
            rnk[a]++;
    }
}
 
// Function to solve the problem and find the Minimum
// Spanning Tree (MST)
int solve(vector<int>& a, int n, int k)
{
    vector<pair<int, int> > vp(n);
    for (int i = 0; i < n; i++) {
        // Store the original index of each element
        vp[i].second = i;
 
        // Store the value of each element
        vp[i].first = a[i];
    }
 
    // Sort elements by their values
    sort(vp.begin(), vp.end());
 
    // Initialize disjoint-set data structures for each
    // element
    for (int i = 0; i < n; i++) {
        make_set(i);
    }
 
    int i = 0;
    // Initialize the total weight of the MST
    int ans = 0;
    while (i < n) {
        // Get the original index of the element
        int idx = vp[i].second;
 
        // If the element value is greater than 'k', break
        if (vp[i].first > k)
            break;
 
        int j = idx + 1;
 
        // Initialize the current GCD value
        int curr_gcd = a[idx];
 
        // Explore elements to the right
        while (j < n && curr_gcd == a[idx]) {
            // Calculate the GCD
            curr_gcd = __gcd(curr_gcd, a[j]);
 
            // If the GCD condition is not met, break
            if (curr_gcd != a[idx])
                break;
 
            int x = find_par(idx);
            int y = find_par(j);
 
            // If they are already in the same
            // component, break
            if (x == y)
                break;
 
            // Union two sets and update 'ans'
            union_sets(x, y);
            ans += a[idx];
            j++;
        }
 
        // Explore elements to the left
        j = idx - 1;
        curr_gcd = a[idx];
        while (j >= 0 && curr_gcd == a[idx]) {
            curr_gcd = __gcd(curr_gcd, a[j]);
 
            // If the GCD condition is not met, break
            if (curr_gcd != a[idx])
                break;
 
            int x = find_par(idx);
            int y = find_par(j);
 
            // If they are already in the same
            // component, break
            if (x == y)
                break;
 
            union_sets(x, y);
            ans = ans + a[idx];
            j--;
        }
        i++;
    }
 
    // Add edges with weight 'k' between adjacent elements
    for (int i = 0; i < n - 1; i++) {
        int x = find_par(i);
        int y = find_par(i + 1);
        if (x != y) {
            union_sets(x, y);
 
            // Update 'ans' with the edge weight 'k'
            ans = ans + k;
        }
    }
    // Return the total weight of the MST
    return ans;
}
 
// Driver Code
int main()
{
    int N = 4, K = 5;
    vector<int> a = { 3, 2, 6, 3 };
    int result = solve(a, N, K);
 
    // Print the total weight of the MST
    cout << result << "\n";
}


Java




import java.util.Arrays;
import java.util.Collections;
import java.util.Vector;
 
public class MinimumSpanningTree {
 
    // Rank array for disjoint-set union
    static Vector<Integer> rnk = new Vector<>(Collections.nCopies(200001, 0));
 
    // Parent array for disjoint-set union
    static Vector<Integer> parent = new Vector<>(Collections.nCopies(200001, 0));
 
    // Function to create a new set with element 'v'
    static void makeSet(int v) {
        // Each element is initially its own parent
        parent.set(v, v);
 
        // Initialize the rank to 0 (used in union)
        rnk.set(v, 0);
    }
 
    // Function to find the representative (parent) of a set
    // containing 'v'
    static int findPar(int v) {
        if (v == parent.get(v))
            return v;
 
        // Path compression for optimization
        parent.set(v, findPar(parent.get(v)));
        return parent.get(v);
    }
 
    // Function to union two sets with elements 'a' and 'b'
    static void unionSets(int a, int b) {
        a = findPar(a);
        b = findPar(b);
        if (a != b) {
            if (rnk.get(a) < rnk.get(b))
                Collections.swap(rnk, a, b);
            parent.set(b, a);
            if (rnk.get(a) == rnk.get(b))
                rnk.set(a, rnk.get(a) + 1);
        }
    }
 
    // Function to solve the problem and find the Minimum
    // Spanning Tree (MST)
    static int solve(Vector<Integer> a, int n, int k) {
        Vector<Pair<Integer, Integer>> vp = new Vector<>(n);
 
        for (int i = 0; i < n; i++) {
            // Store the original index of each element
            vp.add(new Pair<>(a.get(i), i));
 
            // Store the value of each element
            vp.set(i, new Pair<>(a.get(i), i));
        }
 
        // Sort elements by their values
        Collections.sort(vp, (x, y) -> x.first - y.first);
 
        // Initialize disjoint-set data structures for each
        // element
        for (int i = 0; i < n; i++) {
            makeSet(i);
        }
 
        int j = 0;
        // Initialize the total weight of the MST
        int ans = 0;
        while (j < n) {
            // Get the original index of the element
            int idx = vp.get(j).second;
 
            // If the element value is greater than 'k', break
            if (vp.get(j).first > k)
                break;
 
            int i = idx + 1;
 
            // Initialize the current GCD value
            int currGcd = a.get(idx);
 
            // Explore elements to the right
            while (i < n && currGcd == a.get(idx)) {
                // Calculate the GCD
                currGcd = gcd(currGcd, a.get(i));
 
                // If the GCD condition is not met, break
                if (currGcd != a.get(idx))
                    break;
 
                int x = findPar(idx);
                int y = findPar(i);
 
                // If they are already in the same component, break
                if (x == y)
                    break;
 
                // Union two sets and update 'ans'
                unionSets(x, y);
                ans += a.get(idx);
                i++;
            }
 
            // Explore elements to the left
            i = idx - 1;
            currGcd = a.get(idx);
            while (i >= 0 && currGcd == a.get(idx)) {
                currGcd = gcd(currGcd, a.get(i));
 
                // If the GCD condition is not met, break
                if (currGcd != a.get(idx))
                    break;
 
                int x = findPar(idx);
                int y = findPar(i);
 
                // If they are already in the same component, break
                if (x == y)
                    break;
 
                unionSets(x, y);
                ans += a.get(idx);
                i--;
            }
            j++;
        }
 
        // Add edges with weight 'k' between adjacent elements
        for (int i = 0; i < n - 1; i++) {
            int x = findPar(i);
            int y = findPar(i + 1);
            if (x != y) {
                unionSets(x, y);
 
                // Update 'ans' with the edge weight 'k'
                ans += k;
            }
        }
        // Return the total weight of the MST
        return ans;
    }
 
    // Utility function to calculate GCD
    static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
 
    // Driver Code
    public static void main(String[] args) {
        int N = 4, K = 5;
        Vector<Integer> a = new Vector<>(Arrays.asList(3, 2, 6, 3));
        int result = solve(a, N, K);
 
        // Print the total weight of the MST
        System.out.println(result);
    }
 
    static class Pair<X, Y> {
        X first;
        Y second;
 
        public Pair(X first, Y second) {
            this.first = first;
            this.second = second;
        }
    }
}
 
 
// This code is contributed by shivamgupta310570


Python3




# Rank array for disjoint-set union
rnk = [0] * 200001
 
# Parent array for disjoint-set union
parent = [0] * 200001
 
# Function to create a new set with element 'v'
def make_set(v):
    # Each element is initially its own parent
    parent[v] = v
 
    # Initialize the rank to 0 (used in union)
    rnk[v] = 0
 
# Function to find the representative (parent) of a set
# containing 'v'
def find_par(v):
    if v == parent[v]:
        return v
 
    # Path compression for optimization
    parent[v] = find_par(parent[v])
    return parent[v]
 
# Function to union two sets with elements 'a' and 'b'
def union_sets(a, b):
    a = find_par(a)
    b = find_par(b)
    if a != b:
        if rnk[a] < rnk[b]:
            a, b = b, a
        parent[b] = a
        if rnk[a] == rnk[b]:
            rnk[a] += 1
 
# Function to solve the problem and find the Minimum
# Spanning Tree (MST)
def solve(a, n, k):
    vp = [(a[i], i) for i in range(n)]
     
    # Sort elements by their values
    vp.sort()
 
    # Initialize disjoint-set data structures for each
    # element
    for i in range(n):
        make_set(i)
 
    i = 0
    # Initialize the total weight of the MST
    ans = 0
    while i < n:
        # Get the original index of the element
        idx = vp[i][1]
 
        # If the element value is greater than 'k', break
        if vp[i][0] > k:
            break
 
        j = idx + 1
 
        # Initialize the current GCD value
        curr_gcd = a[idx]
 
        # Explore elements to the right
        while j < n and curr_gcd == a[idx]:
            # Calculate the GCD
            curr_gcd = math.gcd(curr_gcd, a[j])
 
            # If the GCD condition is not met, break
            if curr_gcd != a[idx]:
                break
 
            x = find_par(idx)
            y = find_par(j)
 
            # If they are already in the same
            # component, break
            if x == y:
                break
 
            # Union two sets and update 'ans'
            union_sets(x, y)
            ans += a[idx]
            j += 1
 
        # Explore elements to the left
        j = idx - 1
        curr_gcd = a[idx]
        while j >= 0 and curr_gcd == a[idx]:
            curr_gcd = math.gcd(curr_gcd, a[j])
 
            # If the GCD condition is not met, break
            if curr_gcd != a[idx]:
                break
 
            x = find_par(idx)
            y = find_par(j)
 
            # If they are already in the same
            # component, break
            if x == y:
                break
 
            union_sets(x, y)
            ans = ans + a[idx]
            j -= 1
        i += 1
 
    # Add edges with weight 'k' between adjacent elements
    for i in range(n - 1):
        x = find_par(i)
        y = find_par(i + 1)
        if x != y:
            union_sets(x, y)
 
            # Update 'ans' with the edge weight 'k'
            ans = ans + k
 
    # Return the total weight of the MST
    return ans
 
# Driver Code
import math
 
N = 4
K = 5
a = [3, 2, 6, 3]
result = solve(a, N, K)
 
# Print the total weight of the MST
print(result)


C#




using System;
using System.Collections.Generic;
 
class Program {
    // Rank array for disjoint-set union
    static int[] rnk = new int[200001];
 
    // Parent array for disjoint-set union
    static int[] parent = new int[200001];
 
    // Function to create a new set with element 'v'
    static void MakeSet(int v)
    {
        // Each element is initially its own parent
        parent[v] = v;
 
        // Initialize the rank to 0 (used in union)
        rnk[v] = 0;
    }
 
    // Function to find the representative (parent) of a set
    // containing 'v'
    static int FindParent(int v)
    {
        if (v == parent[v])
            return v;
 
        // Path compression for optimization
        return parent[v] = FindParent(parent[v]);
    }
 
    // Function to union two sets with elements 'a' and 'b'
    static void UnionSets(int a, int b)
    {
        a = FindParent(a);
        b = FindParent(b);
        if (a != b) {
            if (rnk[a] < rnk[b])
                Swap(ref a, ref b);
            parent[b] = a;
            if (rnk[a] == rnk[b])
                rnk[a]++;
        }
    }
 
    // Function to solve the problem and find the Minimum
    // Spanning Tree (MST)
    static int Solve(List<int> a, int n, int k)
    {
        List<Tuple<int, int> > vp
            = new List<Tuple<int, int> >(n);
        for (int i = 0; i < n; i++) {
            // Store the original index of each element
            vp.Add(new Tuple<int, int>(a[i], i));
        }
 
        // Sort elements by their values
        vp.Sort();
 
        // Initialize disjoint-set data structures for each
        // element
        for (int i = 0; i < n; i++) {
            MakeSet(i);
        }
 
        int j = 0;
        // Initialize the total weight of the MST
        int ans = 0;
        while (j < n) {
            // Get the original index of the element
            int idx = vp[j].Item2;
 
            // If the element value is greater than 'k',
            // break
            if (vp[j].Item1 > k)
                break;
 
            int i = idx + 1;
 
            // Initialize the current GCD value
            int currGcd = a[idx];
 
            // Explore elements to the right
            while (i < n && currGcd == a[idx]) {
                // Calculate the GCD
                currGcd = Gcd(currGcd, a[i]);
 
                // If the GCD condition is not met, break
                if (currGcd != a[idx])
                    break;
 
                int x = FindParent(idx);
                int y = FindParent(i);
 
                // If they are already in the same
                // component, break
                if (x == y)
                    break;
 
                // Union two sets and update 'ans'
                UnionSets(x, y);
                ans += a[idx];
                i++;
            }
 
            // Explore elements to the left
            i = idx - 1;
            currGcd = a[idx];
            while (i >= 0 && currGcd == a[idx]) {
                currGcd = Gcd(currGcd, a[i]);
 
                // If the GCD condition is not met, break
                if (currGcd != a[idx])
                    break;
 
                int x = FindParent(idx);
                int y = FindParent(i);
 
                // If they are already in the same
                // component, break
                if (x == y)
                    break;
 
                UnionSets(x, y);
                ans = ans + a[idx];
                i--;
            }
            j++;
        }
 
        // Add edges with weight 'k' between adjacent
        // elements
        for (int i = 0; i < n - 1; i++) {
            int x = FindParent(i);
            int y = FindParent(i + 1);
            if (x != y) {
                UnionSets(x, y);
 
                // Update 'ans' with the edge weight 'k'
                ans = ans + k;
            }
        }
        // Return the total weight of the MST
        return ans;
    }
 
    // Function to calculate GCD
    static int Gcd(int a, int b)
    {
        while (b != 0) {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
 
    // Function to swap two values
    static void Swap(ref int a, ref int b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
 
    // Driver Code
    static void Main()
    {
        int N = 4, K = 5;
        List<int> a = new List<int>{ 3, 2, 6, 3 };
        int result = Solve(a, N, K);
 
        // Print the total weight of the MST
        Console.WriteLine(result);
    }
}


Javascript




// Function to create a new set with element 'v'
function makeSet(v, parent, rnk) {
    parent[v] = v;
    rnk[v] = 0;
}
 
// Function to find the representative (parent) of a set containing 'v'
function findPar(v, parent) {
    if (v === parent[v]) {
        return v;
    }
 
    // Path compression for optimization
    parent[v] = findPar(parent[v], parent);
    return parent[v];
}
 
// Function to union two sets with elements 'a' and 'b'
function unionSets(a, b, parent, rnk) {
    a = findPar(a, parent);
    b = findPar(b, parent);
    if (a !== b) {
        if (rnk[a] < rnk[b]) {
            [rnk[a], rnk[b]] = [rnk[b], rnk[a]];
        }
        parent[b] = a;
        if (rnk[a] === rnk[b]) {
            rnk[a]++;
        }
    }
}
 
// Function to solve the problem and find the Minimum Spanning Tree (MST)
function solve(a, n, k) {
    const vp = Array.from({ length: n }, (_, i) => ({ value: a[i], index: i }));
 
    // Sort elements by their values
    vp.sort((x, y) => x.value - y.value);
 
    // Initialize disjoint-set data structures for each element
    const parent = new Array(n);
    const rnk = new Array(n);
    for (let i = 0; i < n; i++) {
        makeSet(i, parent, rnk);
    }
 
    let j = 0;
    // Initialize the total weight of the MST
    let ans = 0;
    while (j < n) {
        // Get the original index of the element
        const idx = vp[j].index;
 
        // If the element value is greater than 'k', break
        if (vp[j].value > k) {
            break;
        }
 
        let i = idx + 1;
        // Initialize the current GCD value
        let currGcd = a[idx];
 
        // Explore elements to the right
        while (i < n && currGcd === a[idx]) {
            // Calculate the GCD
            currGcd = gcd(currGcd, a[i]);
 
            // If the GCD condition is not met, break
            if (currGcd !== a[idx]) {
                break;
            }
 
            const x = findPar(idx, parent);
            const y = findPar(i, parent);
 
            // If they are already in the same component, break
            if (x === y) {
                break;
            }
 
            // Union two sets and update 'ans'
            unionSets(x, y, parent, rnk);
            ans += a[idx];
            i++;
        }
 
        // Explore elements to the left
        i = idx - 1;
        currGcd = a[idx];
        while (i >= 0 && currGcd === a[idx]) {
            currGcd = gcd(currGcd, a[i]);
 
            // If the GCD condition is not met, break
            if (currGcd !== a[idx]) {
                break;
            }
 
            const x = findPar(idx, parent);
            const y = findPar(i, parent);
 
            // If they are already in the same component, break
            if (x === y) {
                break;
            }
 
            unionSets(x, y, parent, rnk);
            ans += a[idx];
            i--;
        }
        j++;
    }
 
    // Add edges with weight 'k' between adjacent elements
    for (let i = 0; i < n - 1; i++) {
        const x = findPar(i, parent);
        const y = findPar(i + 1, parent);
        if (x !== y) {
            unionSets(x, y, parent, rnk);
 
            // Update 'ans' with the edge weight 'k'
            ans += k;
        }
    }
    // Return the total weight of the MST
    return ans;
}
 
// Utility function to calculate GCD
function gcd(a, b) {
    return b === 0 ? a : gcd(b, a % b);
}
 
// Driver Code
const N = 4, K = 5;
const a = [3, 2, 6, 3];
const result = solve(a, N, K);
 
// Print the total weight of the MST
console.log(result);


Output

10







Time Complexity: O(N logN), where N is the size of the input array arr[].
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads