Open In App

Minimize sum of incompatibilities of K equal-length subsets made up of unique elements

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] consisting of N integers and an integer K, the task is to find the minimum sum of incompatibilities of K subsets of equal sizes having unique elements.

The difference between the maximum and the minimum element in a set is known as the incompatibility of a set.

Examples: 

Input: arr[] = {1, 2, 1, 4}, K = 2
Output: 4
Explanation: 
One of the possible ways of distributing the array into K(i.e., 2) subsets is {1, 2} and {1, 4}.
The incompatibility of the first subset = (2 – 1) = 1.
The incompatibility of the second subset = (4 – 1) = 3.
Therefore, the total sum of incompatibilities of both subsets = 1 + 3 = 4, which is the minimum among all possibilities.

Input: arr[] = {6, 3, 8, 1, 3, 1, 2, 2}, K = 4
Output: 6
Explanation: 
One of the possible ways of distributing the array into K subset is: {1, 2}, {2, 3}, {6, 8}, {1, 3}.
The incompatibility of the first subset = (2-1) = 1.
The incompatibility of the second subset = (3-2) = 1.
The incompatibility of the third subset = (8-6) = 2.
The incompatibility of the fourth subset = (3-1) = 2.
Therefore, total sum of incompatibilities of K subset = 1 + 1 + 2 + 2 = 6. And it is also the minimum among all possibilities 

Naive Approach: The simplest approach is to traverse the given array recursively and in each recursion traverse over all possible ways of selecting N/K elements of the array using bitmask and calculate the incompatibility of that subset and then return the minimum among all.

Time Complexity: O(N*23*N)
Auxiliary Space: O(N)

Efficient Approach: The above approach can be optimized using dynamic programming. The given problem can be solved based on the following observations:

  • It can be observed that it requires a 2 state Dynamic programming with Bitmasking say DP(mask, i) to solve the problem where i represents the current position of the array and each binary bit of mask represent if the element has been already selected or not.
  • The transition state will include calculating the incompatibility by selecting a subset of size N/K.
    • Suppose X and Y is minimum and maximum of current set and newmask is another variable with value initially as the mask
    • Now, mark all the N/K elements that have been selected occurs only once in newmask then DP(mask, i) is calculated by (Y – X + min(DP(newmask, i + 1), DP(mask, i))).

Follow the steps below to solve the problem:

  • Initialize a 2D array, say dp[][].
  • Define a recursive function, say dfs (mask, i), to calculate the result:
    • Base Case: If i > K, then return 0.
    • Check if dp[mask][i] != -1, then return dp[mask][i] as the current state is already calculated.
    • Select N/K elements from the array using bitmasking and if it possible to choose i elements of the subset which only occurs once and are not already part of other subsets, then update the current dp state as:

dp[mask][i] = min(dp[mask][i], Y – X + dfs(newmask, i))

  • Return the value of dp[mask][i] as the result in the current recursive call.
  • Call the recursive function dfs(2N-1, 0) and print the value returned by it.

Below is the implementation of the above approach: 

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
int k;
int n;
int goal;
vector<vector<int>> dp;
vector<int> bits;
 
// Recursive function to find
// the minimum required value
int dfs(vector<int> A, int state,int index)
{
   
    // Base Case
    if (index >= k)
    {
        return 0;
    }
 
    // Stores the minimum value
    // of the current state
    int res = 1000;
 
    // If dp[state][index] is
    // already calculated
    if (dp[state][index] != -1) {
 
        // return dp[state][index]
        return dp[state][index];
    }
 
    // Traverse over all the bits
    for (int bit : bits) {
 
        // If count of set bit is N/K
        if (__builtin_popcount(bit)
            == goal) {
 
            // Store the new state after
            // choosing N/K elements
            int newstate = state;
 
            // Stores the minimum and
            // maximum of current subset
            int mn = 100, mx = -1;
 
            // Stores if the elements
            // have been already
            // selected or not
            vector<bool> visit(n+1,false);
 
            // Stores if it is possible
            // to select N/K elements
            bool good = true;
 
            // Traverse over the array
            for (int j = 0; j < n; j++) {
 
                // If not chosen already
                // for another subset
                if ((bit & (1 << j)) != 0) {
 
                    // If already chosen
                    // for another subset
                    // or current subset
                    if (visit[A[j]] == true
                        || (state & (1 << j)) == 0) {
 
                        // Mark the good false
                        good = false;
                        break;
                    }
 
                    // Mark the current
                    // number visited
                    visit[A[j]] = true;
 
                    // Mark the current
                    // position in mask
                    // newstate
                    newstate = newstate
                               ^ (1 << j);
 
                    // Update the maximum
                    // and minimum
                    mx = max(mx,
                                  A[j]);
                    mn = min(mn,
                                  A[j]);
                }
            }
 
            // If good is true then
            // Update the res
            if (good) {
                res = min(
                    res, mx - mn
                             + dfs(A, newstate,
                                   index + 1));
            }
        }
    }
 
    // Update the current sp state
    dp[state][index] = res;
 
    // Return the res
    return res;
}
 
// Function to find the minimum
// incompatibility sum
int minimumIncompatibility(vector<int> A, int K)
{
    n = A.size();
    k = K;
    goal = n / k;
   
    // Stores the count of element
    map<int, int> mp;
 
    // Traverse the array
    for (int i : A) {
 
        // If number i not occurs
        // in Map
        if (mp.find(i)==mp.end()){
            // Put the element
            // in the Map
            mp[i] = 0;
          }
 
        // Increment the count of
        // i in the Hash Map
        mp[i]++;
 
        // If count of i in Map is
        // greater than K then
        // return -1
        if (mp[i] > k)
            return -1;
    }
 
    // Stores all total state
    int state = (1 << n) - 1;
 
    // Traverse over all the state
    for (int i = 0; i <= state; i++) {
 
        // If number of set bit
        // is equal to N/K
        if (__builtin_popcount(i) == goal){
            bits.push_back(i);
        }
    }
 
    // Stores the minimum value
    // at a state
    dp.resize(1<<n,vector<int>(k,-1));
 
    // Initialize the dp state
    // with -1
    // for (int i = 0;
    //      i < dp.ize(); i++) {
    //     Arrays.fill(dp[i], -1);
    // }
 
    // Call the recursive function
    return dfs(A, state, 0);
}
 
// Driver code
int main()
{
 
    vector<int> arr = { 1, 2, 1, 4 };
    int K = 2;
 
    // Function Call
    cout<<(minimumIncompatibility(arr, K));
}
 
// This code is contributed by mohit kumar 29.


Java




// Java program for the above approach
import java.io.*;
import java.util.*;
 
class Solution {
    int k;
    int n;
    int goal;
    int dp[][];
    List<Integer> bits = new ArrayList<>();
 
    // Function to find the minimum
    // incompatibility sum
    public int minimumIncompatibility(
        int[] A, int k)
    {
        this.n = A.length;
        this.k = k;
        goal = n / k;
 
        // Stores the count of element
        Map<Integer, Integer> map
            = new HashMap<>();
 
        // Traverse the array
        for (int i : A) {
 
            // If number i not occurs
            // in Map
            if (!map.containsKey(i))
 
                // Put the element
                // in the Map
                map.put(i, 0);
 
            // Increment the count of
            // i in the Hash Map
            map.put(i, map.get(i) + 1);
 
            // If count of i in Map is
            // greater than K then
            // return -1
            if (map.get(i) > k)
                return -1;
        }
 
        // Stores all total state
        int state = (1 << n) - 1;
 
        // Traverse over all the state
        for (int i = 0; i <= state; i++) {
 
            // If number of set bit
            // is equal to N/K
            if (Integer.bitCount(i) == goal)
                bits.add(i);
        }
 
        // Stores the minimum value
        // at a state
        dp = new int[1 << n][k];
 
        // Initialize the dp state
        // with -1
        for (int i = 0;
             i < dp.length; i++) {
            Arrays.fill(dp[i], -1);
        }
 
        // Call the recursive function
        return dfs(A, state, 0);
    }
 
    // Recursive function to find
    // the minimum required value
    public int dfs(int A[], int state,
                   int index)
    {
        // Base Case
        if (index >= k) {
            return 0;
        }
 
        // Stores the minimum value
        // of the current state
        int res = 1000;
 
        // If dp[state][index] is
        // already calculated
        if (dp[state][index] != -1) {
 
            // return dp[state][index]
            return dp[state][index];
        }
 
        // Traverse over all the bits
        for (int bit : bits) {
 
            // If count of set bit is N/K
            if (Integer.bitCount(bit)
                == goal) {
 
                // Store the new state after
                // choosing N/K elements
                int newstate = state;
 
                // Stores the minimum and
                // maximum of current subset
                int mn = 100, mx = -1;
 
                // Stores if the elements
                // have been already
                // selected or not
                boolean visit[]
                    = new boolean[n + 1];
 
                // Stores if it is possible
                // to select N/K elements
                boolean good = true;
 
                // Traverse over the array
                for (int j = 0; j < n; j++) {
 
                    // If not chosen already
                    // for another subset
                    if ((bit & (1 << j)) != 0) {
 
                        // If already chosen
                        // for another subset
                        // or current subset
                        if (visit[A[j]] == true
                            || (state & (1 << j)) == 0) {
 
                            // Mark the good false
                            good = false;
                            break;
                        }
 
                        // Mark the current
                        // number visited
                        visit[A[j]] = true;
 
                        // Mark the current
                        // position in mask
                        // newstate
                        newstate = newstate
                                   ^ (1 << j);
 
                        // Update the maximum
                        // and minimum
                        mx = Math.max(mx,
                                      A[j]);
                        mn = Math.min(mn,
                                      A[j]);
                    }
                }
 
                // If good is true then
                // Update the res
                if (good) {
                    res = Math.min(
                        res, mx - mn
                                 + dfs(A, newstate,
                                       index + 1));
                }
            }
        }
 
        // Update the current sp state
        dp[state][index] = res;
 
        // Return the res
        return res;
    }
}
 
// Driver Code
class GFG {
 
    public static void main(String[] args)
    {
        Solution st = new Solution();
        int[] arr = { 1, 2, 1, 4 };
        int K = 2;
 
        // Function Call
        System.out.print(
            st.minimumIncompatibility(arr, K));
    }
}


Python3




# Python program for the above approach:
 
k = 0
n = 0
goal = 0
dp = []
bits = []
 
def __builtin_popcount(n):
    count = 0
    while (n > 0):
        count += (n & 1)
        n >>= 1
    return count
 
## Recursive function to find
## the minimum required value
def dfs(A, state, index):
 
    global k
    global n
    global goal
    global dp
    global bits
    ## Base Case
    if (index >= k):
        return 0;
 
    ## Stores the minimum value
    ## of the current state
    res = 1000
 
    ## If dp[state][index] is
    ## already calculated
    if (dp[state][index] != -1):
 
        ## return dp[state][index]
        return dp[state][index];
 
    ## Traverse over all the bits
    for bit in bits:
 
        ## If count of set bit is N/K
        if (__builtin_popcount(bit) == goal):
 
            ## Store the new state after
            ## choosing N/K elements
            newstate = state;
 
            ## Stores the minimum and
            ## maximum of current subset
            mn = 100
            mx = -1
 
            ## Stores if the elements
            ## have been already
            ## selected or not
            visit = [False]*(n+1)
 
            ## Stores if it is possible
            ## to select N/K elements
            good = True
 
            ## Traverse over the array
            for j in range(0, n):
 
                ## If not chosen already
                ## for another subset
                if ((bit & (1 << j)) != 0):
 
                    ## If already chosen
                    ## for another subset
                    ## or current subset
                    if (visit[A[j]] == True or (state & (1 << j)) == 0):
 
                        ## Mark the good false
                        good = False;
                        break;
 
                    ## Mark the current
                    ## number visited
                    visit[A[j]] = True;
 
                    ## Mark the current
                    ## position in mask
                    ## newstate
                    newstate = newstate ^ (1 << j);
 
                    ## Update the maximum
                    ## and minimum
                    mx = max(mx, A[j])
                    mn = min(mn, A[j])
 
            ## If good is True then
            ## Update the res
            if (good):
                res = min(res, mx - mn + dfs(A, newstate, index + 1))
 
    ## Update the current sp state
    dp[state][index] = res
 
    ## Return the res
    return res
 
## Function to find the minimum
## incompatibility sum
def minimumIncompatibility(A, K):
 
    global k
    global n
    global goal
    global dp
    global bits
    n = len(A)
    k = K
    goal = n // k
 
    ## Stores the count of element
    mp = {}
 
    ## Traverse the array
    for i in A:
 
        ## If number i not occurs
        ## in Map
        if (i not in mp):
            ## Put the element
            ## in the Map
            mp[i] = 0
 
        ## Increment the count of
        ## i in the Hash Map
        mp[i]+=1
 
        ## If count of i in Map is
        ## greater than K then
        ## return -1
        if (mp[i] > k):
            return -1;
 
    ## Stores all total state
    state = (1 << n) - 1;
 
    ## Traverse over all the state
    for i in range(state + 1):
 
        ## If number of set bit
        ## is equal to N/K
        if (__builtin_popcount(i) == goal):
            bits.append(i)
 
    ## Stores the minimum value
    ## at a state
    for i in range(1 << n):
        dp.append([])
        for j in range(k):
            dp[i].append(-1)
 
    ## Call the recursive function
    return dfs(A, state, 0);
 
## Driver code
if __name__=='__main__':
 
    arr = [ 1, 2, 1, 4 ]
    K = 2
 
    ## Function Call
    print(minimumIncompatibility(arr, K))
 
    # This code is contributed by subhamgoyal2014.


C#




// C# program for the above approach
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
 
class Solution {
  int k;
  int n;
  int goal;
  int [,]dp;
  List<int> bits = new List<int>();
 
  // Function to find the minimum
  // incompatibility sum
  public int minimumIncompatibility(
    int[] A, int k)
  {
    this.n = A.Length;
    this.k = k;
    goal = n / k;
 
    // Stores the count of element
    Dictionary<int,int> map
      = new Dictionary<int,int>();
 
    // Traverse the array
    foreach(int i in A) {
 
      // If number i not occurs
      // in Map
      if (!map.ContainsKey(i))
 
        // Put the element
        // in the Map
        map[i]= 0;
 
      // Increment the count of
      // i in the Hash Map
      map[i]++;
 
      // If count of i in Map is
      // greater than K then
      // return -1
      if (map[i] > k)
        return -1;
    }
 
    // Stores all total state
    int state = (1 << n) - 1;
 
    // Traverse over all the state
    for (int i = 0; i <= state; i++) {
 
      // If number of set bit
      // is equal to N/K
      if (Convert.ToString(i, 2).Count(c => c == '1') == goal)
        bits.Add(i);
    }
 
    // Stores the minimum value
    // at a state
    dp = new int[1 << n,k];
 
    // Initialize the dp state
    // with -1
    for (int i = 0;i < dp.GetLength(0); i++) {
 
      for (int j = 0;j < dp.GetLength(1); j++) {
        dp[i,j]=-1;
      }
 
    }
 
    // Call the recursive function
    return dfs(A, state, 0);
  }
 
  // Recursive function to find
  // the minimum required value
  public int dfs(int []A, int state,
                 int index)
  {
    // Base Case
    if (index >= k) {
      return 0;
    }
 
    // Stores the minimum value
    // of the current state
    int res = 1000;
 
    // If dp[state][index] is
    // already calculated
    if (dp[state,index] != -1) {
 
      // return dp[state][index]
      return dp[state,index];
    }
 
    // Traverse over all the bits
    foreach(int bit in bits) {
 
      // If count of set bit is N/K
      if(Convert.ToString(bit, 2).Count(c => c == '1')== goal) {
 
        // Store the new state after
        // choosing N/K elements
        int newstate = state;
 
        // Stores the minimum and
        // maximum of current subset
        int mn = 100, mx = -1;
 
        // Stores if the elements
        // have been already
        // selected or not
        bool []visit
          = new bool[n + 1];
 
        // Stores if it is possible
        // to select N/K elements
        bool good = true;
 
        // Traverse over the array
        for (int j = 0; j < n; j++) {
 
          // If not chosen already
          // for another subset
          if ((bit & (1 << j)) != 0) {
 
            // If already chosen
            // for another subset
            // or current subset
            if (visit[A[j]] == true
                || (state & (1 << j)) == 0) {
 
              // Mark the good false
              good = false;
              break;
            }
 
            // Mark the current
            // number visited
            visit[A[j]] = true;
 
            // Mark the current
            // position in mask
            // newstate
            newstate = newstate
              ^ (1 << j);
 
            // Update the maximum
            // and minimum
            mx = Math.Max(mx,
                          A[j]);
            mn = Math.Min(mn,
                          A[j]);
          }
        }
 
        // If good is true then
        // Update the res
        if (good) {
          res = Math.Min(
            res, mx - mn
            + dfs(A, newstate,
                  index + 1));
        }
      }
    }
 
    // Update the current sp state
    dp[state,index] = res;
 
    // Return the res
    return res;
  }
}
 
// Driver Code
class GFG {
 
  public static void Main()
  {
    Solution st = new Solution();
    int[] arr = { 1, 2, 1, 4 };
    int K = 2;
 
    // Function Call
    Console.Write(
      st.minimumIncompatibility(arr, K));
  }
}
 
// This code is contributed by rutvik_56.


Javascript




<script>
// Javascript program for the above approach
 
let k,n,goal;
let dp;
let bits = [];
 
// Function to find the minimum
// incompatibility sum
function minimumIncompatibility(A,K)
{
    n = A.length;
    k = K;
    goal = Math.floor(n / k);
     
    // Stores the count of element
        let map = new Map();
  
        // Traverse the array
        for (let i=0;i< A.length;i++) {
  
            // If number i not occurs
            // in Map
            if (!map.has(A[i]))
  
                // Put the element
                // in the Map
                map.set(A[i], 0);
  
            // Increment the count of
            // i in the Hash Map
            map.set(A[i], map.get(A[i]) + 1);
  
            // If count of i in Map is
            // greater than K then
            // return -1
            if (map.get(A[i]) > k)
                return -1;
        }
  
        // Stores all total state
        let state = (1 << n) - 1;
  
        // Traverse over all the state
        for (let i = 0; i <= state; i++) {
  
            // If number of set bit
            // is equal to N/K
            if (i.toString(2).split('0').join('').length == goal)
                bits.push(i);
        }
  
        // Stores the minimum value
        // at a state
        dp = new Array(1 << n);
  
        // Initialize the dp state
        // with -1
        for (let i = 0;
            i < dp.length; i++) {
            dp[i]=new Array(k);
            for(let j=0;j<k;j++)
                dp[i][j]=-1;
        }
  
        // Call the recursive function
        return dfs(A, state, 0);
}
 
// Recursive function to find
// the minimum required value
function dfs(A,state,index)
{
    // Base Case
        if (index >= k) {
            return 0;
        }
  
        // Stores the minimum value
        // of the current state
        let res = 1000;
  
        // If dp[state][index] is
        // already calculated
        if (dp[state][index] != -1) {
  
            // return dp[state][index]
            return dp[state][index];
        }
  
        // Traverse over all the bits
        for (let bit=0;bit< bits.length;bit++) {
  
            // If count of set bit is N/K
            if (bits[bit].toString(2).split('0').join('').length
                == goal) {
  
                // Store the new state after
                // choosing N/K elements
                let newstate = state;
  
                // Stores the minimum and
                // maximum of current subset
                let mn = 100, mx = -1;
  
                // Stores if the elements
                // have been already
                // selected or not
                let visit
                    = new Array(n + 1);
                    for(let i=0;i<=n;i++)
                    {
                        visit[i]=false;
                    }
  
                // Stores if it is possible
                // to select N/K elements
                let good = true;
  
                // Traverse over the array
                for (let j = 0; j < n; j++) {
  
                    // If not chosen already
                    // for another subset
                    if ((bits[bit] & (1 << j)) != 0) {
  
                        // If already chosen
                        // for another subset
                        // or current subset
                        if (visit[A[j]] == true
                            || (state & (1 << j)) == 0) {
  
                            // Mark the good false
                            good = false;
                            break;
                        }
  
                        // Mark the current
                        // number visited
                        visit[A[j]] = true;
  
                        // Mark the current
                        // position in mask
                        // newstate
                        newstate = newstate
                                   ^ (1 << j);
  
                        // Update the maximum
                        // and minimum
                        mx = Math.max(mx,
                                      A[j]);
                        mn = Math.min(mn,
                                      A[j]);
                    }
                }
  
                // If good is true then
                // Update the res
                if (good) {
                    res = Math.min(
                        res, mx - mn
                                 + dfs(A, newstate,
                                       index + 1));
                }
            }
        }
  
        // Update the current sp state
        dp[state][index] = res;
  
        // Return the res
        return res;
}
 
// Driver Code
let arr=[1, 2, 1, 4];
let K = 2;
document.write(minimumIncompatibility(arr, K))
 
 
// This code is contributed by unknown2108
</script>


Output: 

4

 

Time Complexity: O(N2*22*N)
Auxiliary Space: O(N) 



Last Updated : 15 Jun, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads