Open In App

Partition of a set into K subsets with equal sum

Last Updated : 26 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

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

Examples:  

Input: arr[] = [2, 1, 4, 5, 6], k = 3 
Output: true
Explanation: Possible subsets of the given array are [2, 4], [1, 5] and [6]

Input: arr[] = [2, 1, 5, 5, 6], k = 3 
Output: false
Explanation: It is not possible to divide above array into 3 parts with equal sum.

Approach:

We can solve this problem recursively by exploring all possible combinations for each of the k subsets. This is achieved by tracking the sum of the current subset and using a boolean array (taken) to check if an element has already been included in a subset or not.

Base Cases:

  • if k = 1, the entire array forms the only subset.
  • if n < k, it is impossible to divide the array into k subset since there are not enough elements.
  • if the total sum of array is not divisible by k, equal partitioning is not feasible.

if these condition are met, the task reduces to dividing the array into k subsets , each with sum equal to arraySum/k.

Recursive Cases:

The recursive function attempts to add elements to each subset:

  • If a subset’s sum matches the required value, the function moves to the next subset.
  • If a subset doesn’t reach the target, the function backtracks and tries other combinations of elements.

Once k-1 subsets reach the required sum, the remaining elements automatically form the final subset with the desired sum, confirming that partitioning is possible.
This process continues until either all subsets are formed successfully or no valid partitioning is found.

C++
// C++ program to check whether an array can be
// partitioned into K subsets of equal sum

#include <bits/stdc++.h>
using namespace std;

bool isKPartitionPossible(vector<int> &arr, vector<int> &subsetSum,
                          vector<bool> &taken, int target, int k,
                          int n, int currIdx, int limitIdx) {

    // If the current subset sum matches the target
    if (subsetSum[currIdx] == target) {
      
        // If all but one subset are filled, the 
       // last subset is guaranteed to work
        if (currIdx == k - 2)
            return true;
        return isKPartitionPossible(arr, subsetSum, taken,
                                    target, k, n, currIdx + 1, n - 1);
    }

    // Try including each element in the current subset
    for (int i = limitIdx; i >= 0; i--) {
      
        // Skip if the element is already used
        if (taken[i])
            continue;
        int temp = subsetSum[currIdx] + arr[i];
        if (temp <= target) {
          
            // Only proceed if it doesn't exceed the target
            taken[i] = true;
            subsetSum[currIdx] += arr[i];
            if (isKPartitionPossible(arr, subsetSum, taken,
                                     target, k, n, currIdx, i - 1))
                return true;

            // Backtrack
            taken[i] = false;
            subsetSum[currIdx] -= arr[i];
        }
    }
    return false;
}

bool isKPartitionPossible(vector<int> &arr, int k) {
  
    int n = arr.size(), sum = accumulate(arr.begin(), arr.end(), 0);

    // If only one subset is needed, it's always possible
    if (k == 1)
        return true;

    // Check if partition is impossible
    if (n < k || sum % k != 0)
        return false;

    int target = sum / k;
    vector<int> subsetSum(k, 0);
    vector<bool> taken(n, false);

    // Initialize first subset with the last element
    subsetSum[0] = arr[n - 1];
    taken[n - 1] = true;

    // Recursively check for partitions
    return isKPartitionPossible(arr, subsetSum, taken,
                                target, k, n, 0, n - 1);
}

int main() {
    vector<int> arr = {2, 1, 4, 5, 3, 3};
    int k = 3;

    if (isKPartitionPossible(arr, k))
        cout << "true";
    else
        cout << "false";

    return 0;
}
Java
// Java program to check whether an array can be
// partitioned into K subsets of equal sum

import java.util.Arrays;

class GfG {
 
    static boolean
    isKPartitionPossible(int[] arr, int[] subsetSum,
                         boolean[] taken, int target, int k,
                         int n, int currIdx, int limitIdx) {
      
        // If the current subset sum matches the target
        if (subsetSum[currIdx] == target) {
          
            // If all but one subset are filled, the last
            // subset is guaranteed to work
            if (currIdx == k - 2)
                return true;
            return isKPartitionPossible(arr, subsetSum,
                                        taken, target, k, n,
                                        currIdx + 1, n - 1);
        }

        // Try including each element in the current subset
        for (int i = limitIdx; i >= 0; i--) {
            if (taken[i])  
                continue;

            int temp = subsetSum[currIdx] + arr[i];
            if (temp
                <= target) { 
              
               // Only proceed if it doesn't
               // exceed the target
                taken[i] = true;
                subsetSum[currIdx] += arr[i];

                if (isKPartitionPossible(arr, subsetSum,
                                         taken, target, k,
                                         n, currIdx, i - 1))
                    return true;

                // Backtrack
                taken[i] = false;
                subsetSum[currIdx] -= arr[i];
            }
        }
        return false;
    }
  
    static boolean isKPartitionPossible(int[] arr, int k) {
        int n = arr.length;
        int sum = Arrays.stream(arr).sum();

        // If only one subset is needed, it's always
        // possible
        if (k == 1)
            return true;

        // Check if partition is impossible
        if (n < k || sum % k != 0)
            return false;

        int target = sum / k;
        int[] subsetSum = new int[k];
        boolean[] taken = new boolean[n];

        // Initialize the first subset with the
      	// last element
        subsetSum[0] = arr[n - 1];
        taken[n - 1] = true;

        // Recursively check for partitions
        return isKPartitionPossible(arr, subsetSum, taken,
                                    target, k, n, 0, n - 1);
    }

    public static void main(String[] args) {
        int[] arr = { 2, 1, 4, 5, 3, 3 };
        int k = 3;

        if (isKPartitionPossible(arr, k))
            System.out.println("true");
        else
            System.out.println("false");
    }
}
Python
# Python3 program to check whether an array can be
# partitioned into K subsets of equal sum


def isKPartitionPossible(arr, subsetSum, taken,\
                         target, k, n, currIdx, limitIdx):
  
    # If the current subset sum matches the target
    if subsetSum[currIdx] == target:
      
        # If all but one subset are filled, the last
        # subset is guaranteed to work
        if currIdx == k - 2:
            return True
        return isKPartitionPossible(arr, subsetSum, taken,\
                                    target, k, n, currIdx + 1, n - 1)

    # Try including each element in the current subset
    for i in range(limitIdx, -1, -1):
      
      # Skip if the element is already used
        if taken[i]:   
            continue

        temp = subsetSum[currIdx] + arr[i]
        
        # Only proceed if it doesn't exceed the target
        if temp <= target:   
            taken[i] = True
            subsetSum[currIdx] += arr[i]

            if isKPartitionPossible(arr, subsetSum, taken,\
                                    target, k, n, currIdx, i - 1):
                return True

            # Backtrack
            taken[i] = False
            subsetSum[currIdx] -= arr[i]

    return False


def isKPartitionPossibleMain(arr, k):
    n = len(arr)
    totalSum = sum(arr)

    # If only one subset is needed, it's
    # always possible
    if k == 1:
        return True

    # Check if partition is impossible
    if n < k or totalSum % k != 0:
        return False

    target = totalSum // k
    subsetSum = [0] * k
    taken = [False] * n

    # Initialize the first subset with the 
    # last element
    subsetSum[0] = arr[-1]
    taken[-1] = True

    # Recursively check for partitions
    return isKPartitionPossible(arr, subsetSum, taken,\
                                target, k, n, 0, n - 1)

 
arr = [2, 1, 4, 5, 3, 3]
k = 3

if isKPartitionPossibleMain(arr, k):
    print("true")
else:
    print("false")
C#
// C# program to check whether an array can be
// partitioned into K subsets of equal sum

using System;

class GfG {
    static bool
    isKPartitionPossible(int[] arr, int[] subsetSum,
                         bool[] taken, int target, int k,
                         int n, int currIdx, int limitIdx) {

        // If the current subset sum matches the target
        if (subsetSum[currIdx] == target) {

            // If all but one subset are filled, the last
            // subset is guaranteed to work
            if (currIdx == k - 2)
                return true;
            return isKPartitionPossible(arr, subsetSum,
                                        taken, target, k, n,
                                        currIdx + 1, n - 1);
        }

        // Try including each element in the current subset
        for (int i = limitIdx; i >= 0; i--) {

            // Skip if the element is already used
            if (taken[i])
                continue;

            int temp = subsetSum[currIdx] + arr[i];
            if (temp <= target) {
                taken[i] = true;
                subsetSum[currIdx] += arr[i];

                if (isKPartitionPossible(arr, subsetSum,
                                         taken, target, k,
                                         n, currIdx, i - 1))
                    return true;

                // Backtrack
                taken[i] = false;
                subsetSum[currIdx] -= arr[i];
            }
        }
        return false;
    }

    static bool isKPartitionPossibleMain(int[] arr, int k) {
        int n = arr.Length;
        int totalSum = 0;

        // Calculate the sum of the array
        foreach(var num in arr) { totalSum += num; }

        // If only one subset is needed, it's always
        // possible
        if (k == 1)
            return true;

        // Check if partition is impossible
        if (n < k || totalSum % k != 0)
            return false;

        int target = totalSum / k;
        int[] subsetSum = new int[k];
        bool[] taken = new bool[n];

        // Initialize the first subset with the last element
        subsetSum[0] = arr[n - 1];
        taken[n - 1] = true;

        // Recursively check for partitions
        return isKPartitionPossible(arr, subsetSum, taken,
                                    target, k, n, 0, n - 1);
    }

    static void Main() {
        int[] arr = { 2, 1, 4, 5, 3, 3 };
        int k = 3;

        if (isKPartitionPossibleMain(arr, k))
            Console.WriteLine("true");
        else
            Console.WriteLine("false");
    }
}
JavaScript
// JavaScript program to check whether an array can be
// partitioned into K subsets of equal sum 
 
 
function isKPartitionPossible(arr, subsetSum, taken, target,
                              k, n, currIdx, limitIdx) {
                              
    // If the current subset sum matches the target
    if (subsetSum[currIdx] === target) {
    
        // If all but one subset are filled, the last subset
        // is guaranteed to work
        if (currIdx === k - 2) {
            return true;
        }
        return isKPartitionPossible(arr, subsetSum, taken,
                                    target, k, n,
                                    currIdx + 1, n - 1);
    }

    // Try including each element in the current subset
    for (let i = limitIdx; i >= 0; i--) {
        if (taken[i])  
            continue;

        let temp = subsetSum[currIdx] + arr[i];
        if (temp <= target) {              
            taken[i] = true;
            subsetSum[currIdx] += arr[i];

            if (isKPartitionPossible(arr, subsetSum, taken,
                                     target, k, n, currIdx,
                                     i - 1)) {
                return true;
            }

            // Backtrack
            taken[i] = false;
            subsetSum[currIdx] -= arr[i];
        }
    }
    return false;
}
 
function isKPartitionPossibleMain(arr, k) {
    let n = arr.length;
    let totalSum = arr.reduce((sum, num) => sum + num, 0);

    // If only one subset is needed, it's always possible
    if (k === 1)
        return true;

    // Check if partition is impossible
    if (n < k || totalSum % k !== 0)
        return false;

    let target = totalSum / k;
    let subsetSum = new Array(k).fill(0);
    let taken = new Array(n).fill(false);

    // Initialize the first subset with the last element
    subsetSum[0] = arr[n - 1];
    taken[n - 1] = true;

    // Recursively check for partitions
    return isKPartitionPossible(arr, subsetSum, taken,
                                target, k, n, 0, n - 1);
}
 
let arr = [ 2, 1, 4, 5, 3, 3 ];
let k = 3;

if (isKPartitionPossibleMain(arr, k)) {
    console.log("true");
}
else {
    console.log("false");
}

Output
true

Time Complexity: O(k*2^n) For each k subset, The algorithm checks all possible subsets of the array (which is 2^n).
Auxilary Space: O(n) where n is the length of array. 

Related article:


Next Article
Article Tags :
Practice Tags :

Similar Reads