Partition of a set into K subsets with equal sum using BitMask and DP

Given an integer array arr[] of consisting of N integers, the task is check if it is possible to divide the given array into K non-empty subsets of equal sum such that every array element is part of a single subset.

Examples:

Input: arr[] = {2, 1, 4, 5, 6}, K = 3
Output: Yes
Explanation:
Possible subsets of given array are {2, 4}, (1, 5} and {6}

Input: arr[] = {2, 1, 5, 5, 6}, K = 3
Output: No

For the recursive approach, refer to Partition of a set into K subsets with equal sum.



Approach:
Follow the steps below to solve the problem:

  • The idea is to use mask to determine the current state. The current state will tell us about the subset already formed ( which numbers are already selected ).
    For example: arr[] = [2, 1, 4, 3, 5, 6, 2], mask = (1100101), which means that { 2, 1, 5, 2 } are already chosen in the current mask.
  • For any current state mask, the jth element will be added to it based on the following two conditions:
    1. The jth bit is not set in the mask (mask&(1<<j) == 0)
    2. sum (mask) + arr[j] <= target ( where target = (Sum of array elements) / K)
  • Maintian a table dp[] such that dp[i] store the sum of elements in mask i. So, the dp transitions will be:

    dp[i | (1 << j)] = (dp[i] + arr[j]) % target
    Illustration:
    arr [ ] = [4, 3, 2, 3, 5, 2, 1], K = 4, tar = 5
    dp["1100101"] implies that { 4, 3, 5, 1 } are chosen
    Hence, Sum = 4 + 3 + 5 + 1 = 13, 13 % 5 = 3.
    Hence, dp["1100101"] = 3

    If dp["11111…1111"] == 0 then that means we can find the solution.

Below is the implementation of above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to check if the
// given array can be partitioned
// into K subsets with equal sum
#include <bits/stdc++.h>
using namespace std;
  
// Function to check whether
// K required partitions
// are possible or not
bool isKPartitionPossible(int arr[],
                          int N, int K)
{
    if (K == 1)
        // Return true as the
        // entire array is the
        // answer
        return true;
  
    // If total number of
    // partitions exceeds
    // size of the array
    if (N < K)
        return false;
  
    int sum = 0;
    for (int i = 0; i < N; i++)
        sum += arr[i];
    // If the array sum is not
    // divisible by K
    if (sum % K != 0)
        // No such partitions are
        // possible
        return false;
  
    // Required sum of
    // each subset
    int target = sum / K;
  
    // Initialize dp array with -1
    int dp[(1 << 15)];
    for (int i = 0; i < (1 << N); i++)
        dp[i] = -1;
  
    // Sum of empty subset
    // is zero
    dp[0] = 0;
  
    // Iterate over all subsets/masks
    for (int mask = 0; mask < (1 << N); mask++) {
        // if current mask is invalid, continue
        if (dp[mask] == -1)
            continue;
  
        // Iterate over all array elements
        for (int i = 0; i < N; i++) {
            // Check if the current element
            // can be added to the current
            // subset/mask
            if (!(mask & (1 << i))
                && dp[mask]
                           + arr[i]
                       <= target) {
                // transition
                dp[mask | (1 << i)]
                    = (dp[mask]
                       + arr[i])
                      % target;
            }
        }
    }
  
    if (dp[(1 << N) - 1] == 0)
        return true;
    else
        return false;
}
  
// Driver Code
int main()
{
    int arr[] = { 2, 1, 4, 5, 3, 3 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int K = 3;
  
    if (isKPartitionPossible(arr, N, K)) {
        cout << "Partitions into equal ";
        cout << "sum is possible.\n";
    }
    else {
        cout << "Partitions into equal ";
        cout << "sum is not possible.\n";
    }
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to check if the
// given array can be partitioned
// into K subsets with equal sum
import java.util.*;
  
class GFG{
  
// Function to check whether
// K required partitions
// are possible or not
static boolean isKPartitionPossible(int arr[],
                                    int N, int K)
{
    if (K == 1)
      
        // Return true as the
        // entire array is the
        // answer
        return true;
  
    // If total number of
    // partitions exceeds
    // size of the array
    if (N < K)
        return false;
  
    int sum = 0;
    for(int i = 0; i < N; i++)
       sum += arr[i];
         
    // If the array sum is not
    // divisible by K
    if (sum % K != 0)
      
        // No such partitions are
        // possible
        return false;
  
    // Required sum of
    // each subset
    int target = sum / K;
  
    // Initialize dp array with -1
    int []dp = new int[(1 << 15)];
    for(int i = 0; i < (1 << N); i++)
       dp[i] = -1;
  
    // Sum of empty subset
    // is zero
    dp[0] = 0;
  
    // Iterate over all subsets/masks
    for(int mask = 0; mask < (1 << N); mask++) 
    {
         
       // if current mask is invalid, continue
       if (dp[mask] == -1)
           continue;
         
       // Iterate over all array elements
       for(int i = 0; i < N; i++)
       {
            
          // Check if the current element
          // can be added to the current
          // subset/mask
          if (((mask & (1 << i)) == 0) && 
             dp[mask] + arr[i] <= target) 
          {
                
              // Transition
              dp[mask | (1 << i)] = (dp[mask] + 
                                      arr[i]) % 
                                      target;
          }
       }
    }
  
    if (dp[(1 << N) - 1] == 0)
        return true;
    else
        return false;
}
  
// Driver Code
public static void main(String[] args)
{
    int arr[] = { 2, 1, 4, 5, 3, 3 };
    int N = arr.length;
    int K = 3;
  
    if (isKPartitionPossible(arr, N, K))
    {
        System.out.print("Partitions into equal ");
        System.out.print("sum is possible.\n");
    }
    else
    {
        System.out.print("Partitions into equal ");
        System.out.print("sum is not possible.\n");
    }
}
}
  
// This code is contributed by Amit Katiyar

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to check if the
# given array can be partitioned
# into K subsets with equal sum
  
# Function to check whether
# K required partitions
# are possible or not
def isKPartitionPossible(arr, N, K):
      
    if (K == 1):
          
        # Return true as the
        # entire array is the
        # answer
        return True
  
    # If total number of
    # partitions exceeds
    # size of the array
    if (N < K):
        return False
  
    sum = 0
    for i in range(N):
        sum += arr[i]
          
    # If the array sum is not
    # divisible by K
    if (sum % K != 0):
          
        # No such partitions are
        # possible
        return False
  
    # Required sum of
    # each subset
    target = sum / K
  
    # Initialize dp array with -1
    dp = [0 for i in range(1 << 15)]
    for i in range((1 << N)):
        dp[i] = -1
  
    # Sum of empty subset
    # is zero
    dp[0] = 0
  
    # Iterate over all subsets/masks
    for mask in range((1 << N)):
          
        # If current mask is invalid,
        # continue
        if (dp[mask] == -1):
            continue
  
        # Iterate over all array elements
        for i in range(N):
              
            # Check if the current element
            # can be added to the current
            # subset/mask
            if ((mask & (1 << i) == 0) and 
              dp[mask] + arr[i] <= target):
                  
                # Transition
                dp[mask | (1 << i)] = ((dp[mask] + 
                                        arr[i]) %
                                        target)
  
    if (dp[(1 << N) - 1] == 0):
        return True
    else:
        return False
  
# Driver Code
if __name__ == '__main__':
      
    arr = [ 2, 1, 4, 5, 3, 3 ]
    N = len(arr)
    K = 3
  
    if (isKPartitionPossible(arr, N, K)):
        print("Partitions into equal "\
              "sum is possible.")
    else:
        print("Partitions into equal sum "\
              "is not possible.")
  
# This code is contributed by Surendra_Gangwar

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to check if the
// given array can be partitioned
// into K subsets with equal sum
using System;
  
class GFG{
  
// Function to check whether
// K required partitions
// are possible or not
static bool isKPartitionPossible(int []arr,
                                 int N, int K)
{
    if (K == 1)
          
        // Return true as the
        // entire array is the
        // answer
        return true;
  
    // If total number of
    // partitions exceeds
    // size of the array
    if (N < K)
        return false;
  
    int sum = 0;
    for(int i = 0; i < N; i++)
       sum += arr[i];
          
    // If the array sum is not
    // divisible by K
    if (sum % K != 0)
      
        // No such partitions are
        // possible
        return false;
  
    // Required sum of
    // each subset
    int target = sum / K;
  
    // Initialize dp array with -1
    int []dp = new int[(1 << 15)];
    for(int i = 0; i < (1 << N); i++)
       dp[i] = -1;
  
    // Sum of empty subset
    // is zero
    dp[0] = 0;
  
    // Iterate over all subsets/masks
    for(int mask = 0; mask < (1 << N); mask++) 
    {
         
       // If current mask is invalid, continue
       if (dp[mask] == -1)
           continue;
         
       // Iterate over all array elements
       for(int i = 0; i < N; i++)
       {
             
          // Check if the current element
          // can be added to the current
          // subset/mask
          if (((mask & (1 << i)) == 0) && 
             dp[mask] + arr[i] <= target)
          {
                
              // Transition
              dp[mask | (1 << i)] = (dp[mask] + 
                                      arr[i]) % 
                                      target;
          }
       }
    }
  
    if (dp[(1 << N) - 1] == 0)
        return true;
    else
        return false;
}
  
// Driver Code
public static void Main(String[] args)
{
    int []arr = { 2, 1, 4, 5, 3, 3 };
    int N = arr.Length;
    int K = 3;
  
    if (isKPartitionPossible(arr, N, K))
    {
        Console.Write("Partitions into equal ");
        Console.Write("sum is possible.\n");
    }
    else
    {
        Console.Write("Partitions into equal ");
        Console.Write("sum is not possible.\n");
    }
}
}
  
// This code is contributed by Amit Katiyar

chevron_right



Output:

Partitions into equal sum is possible.

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

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.