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++ 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 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));
}
} |
# 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# 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. |
<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> |
4
Time Complexity: O(N2*22*N)
Auxiliary Space: O(N)