1

I'm going through an exercise to partition a set into K subsets with equal sum. Let's say

Input : arr = [2, 1, 4, 5, 6], K = 3
Output : Yes
we can divide above array into 3 parts with equal
sum as [[2, 4], [1, 5], [6]]

I found a solution here, http://www.geeksforgeeks.org/partition-set-k-subsets-equal-sum/

// C++ program to check whether an array can be
// partitioned into K subsets of equal sum
#include <bits/stdc++.h>
using namespace std;

// Recursive Utility method to check K equal sum
// subsetition of array
/**
    array           - given input array
    subsetSum array   - sum to store each subset of the array
    taken           - boolean array to check whether element
                      is taken into sum partition or not
    K               - number of partitions needed
    N               - total number of element in array
    curIdx          - current subsetSum index
    limitIdx        - lastIdx from where array element should
                      be taken */
bool isKPartitionPossibleRec(int arr[], int subsetSum[], bool taken[],
                   int subset, int K, int N, int curIdx, int limitIdx)
{
    if (subsetSum[curIdx] == subset)
    {
        /*  current index (K - 2) represents (K - 1) subsets of equal
            sum last partition will already remain with sum 'subset'*/
        if (curIdx == K - 2)
            return true;

        //  recursive call for next subsetition
        return isKPartitionPossibleRec(arr, subsetSum, taken, subset,
                                            K, N, curIdx + 1, N - 1);
    }

    //  start from limitIdx and include elements into current partition
    for (int i = limitIdx; i >= 0; i--)
    {
        //  if already taken, continue
        if (taken[i])
            continue;
        int tmp = subsetSum[curIdx] + arr[i];

        // if temp is less than subset then only include the element
        // and call recursively
        if (tmp <= subset)
        {
            //  mark the element and include into current partition sum
            taken[i] = true;
            subsetSum[curIdx] += arr[i];
            bool nxt = isKPartitionPossibleRec(arr, subsetSum, taken,
                                            subset, K, N, curIdx, i - 1);

            // after recursive call unmark the element and remove from
            // subsetition sum
            taken[i] = false;
            subsetSum[curIdx] -= arr[i];
            if (nxt)
                return true;
        }
    }
    return false;
}

//  Method returns true if arr can be partitioned into K subsets
// with equal sum
bool isKPartitionPossible(int arr[], int N, int K)
{
    //  If K is 1, then complete array will be our answer
    if (K == 1)
        return true;

    //  If total number of partitions are more than N, then
    // division is not possible
    if (N < K)
        return false;

    // if array sum is not divisible by K then we can't divide
    // array into K partitions
    int sum = 0;
    for (int i = 0; i < N; i++)
        sum += arr[i];
    if (sum % K != 0)
        return false;

    //  the sum of each subset should be subset (= sum / K)
    int subset = sum / K;
    int subsetSum[K];
    bool taken[N];

    //  Initialize sum of each subset from 0
    for (int i = 0; i < K; i++)
        subsetSum[i] = 0;

    //  mark all elements as not taken
    for (int i = 0; i < N; i++)
        taken[i] = false;

    // initialize first subsubset sum as last element of
    // array and mark that as taken
    subsetSum[0] = arr[N - 1];
    taken[N - 1] = true;

    //  call recursive method to check K-substitution condition
    return isKPartitionPossibleRec(arr, subsetSum, taken,
                                     subset, K, N, 0, N - 1);
}

//  Driver code to test above methods
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 sum is possible.\n";
    else
        cout << "Partitions into equal sum is not possible.\n";
}

This works in all scenarios.

Question

  1. Let's say if I pass arr = [4, 4, 1, 3, 2, 3, 2, 1] and k = 4,the algorithm tried to solve it by adding 1+2+2 and then, 3+3 or 3+1 and so on. It doesn't gets the partition and finally solves it to [[4,1], [4,1], [3,2], [3,2]]. I am not sure how does this algorithm finds the alternative? I'm not able to follow up with the recursion.
  2. What are the ways to solve it? Is the backtracking the only way?

Thanks!

moustacheman
  • 1,424
  • 4
  • 21
  • 47
  • 1
    You do realize this problem is NP hard. Partitioning into 2 has a simple pseudo polynomial time algorithm in dynamic programming haven't thought about k. But obviously since for k=2 the general case is np hard so is this problem. – Meir Maor Nov 29 '17 at 18:28
  • My question is like, when the array is `4, 4, 1, 3, 2, 3, 2, 1`, the algorithm tried to solve it by adding `1+2+2` and then, `3+3` or `3+1` and so on. It doesn't gets the partition and finally solves it to [[4,1], [4,1], [3,2], [3,2]]. I am not sure how does this algorithm finds the alternative? – moustacheman Nov 29 '17 at 18:34
  • What does "doesn't gets the partition" mean? – j_random_hacker Nov 29 '17 at 18:36
  • @j_random_hacker I mean when the array `4, 4, 1, 3, 2, 3, 2, 1`, it tries [[2,2,1] [4,1]] which is not K times partition with equal sum. – moustacheman Nov 29 '17 at 18:38
  • I still don't really understand what you mean... Is [[2,2,1], [4,1]] its first attempt? It's not surprising that this first attempt is not a valid solution; the whole design of backtracking algorithms like this one is to keep trying solutions until a valid one is found. This can take a long time. – j_random_hacker Nov 29 '17 at 18:41
  • Hi, I have a recursive solution but it keeps getting TLE on the last-second test case. Not sure what I am missing. Can anyone help? Code: https://pastebin.com/yRUSji89 Thanks in adv. – Harsh Chaplot May 07 '22 at 11:03

0 Answers0