Skip to content
Related Articles

Related Articles

Minimize sum of incompatibilities of K equal-length subsets made up of unique elements
  • Difficulty Level : Expert
  • Last Updated : 09 Mar, 2021

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 tthe 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
            // selsected 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
// incomatibility 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;
 
    // Travere 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));
 
    // Intiallize 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
    // incomatibility 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;
 
        // Travere 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];
 
        // Intiallize 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
                // selsected 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));
    }
}

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
  // incomatibility 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;
 
    // Travere 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];
 
    // Intiallize 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
        // selsected 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.

 
 

Output: 
4

 

 

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

 

Attention reader! Don’t stop learning now. Get hold of all the important mathematical concepts for competitive programming with the Essential Maths for CP Course at a student-friendly price. To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

My Personal Notes arrow_drop_up
Recommended Articles
Page :