Algorithm 将集合划分为等和的K个子集

Algorithm 将集合划分为等和的K个子集,algorithm,recursion,data-structures,backtracking,subset-sum,Algorithm,Recursion,Data Structures,Backtracking,Subset Sum,我正在做一个练习,把一个集合分成K个等和的子集。 比方说 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]] 我在这里找到了解决办法, //C++程序检查数组是否可以 //划分为等和的K个子集 #包括 使用名称空间std; //检验K等和的递归实用方法 //数组的子竞争 /** 数组-给

我正在做一个练习,把一个集合分成K个等和的子集。 比方说

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]]
我在这里找到了解决办法,

<代码> //C++程序检查数组是否可以 //划分为等和的K个子集 #包括 使用名称空间std; //检验K等和的递归实用方法 //数组的子竞争 /** 数组-给定的输入数组 subsetSum array—用于存储数组的每个子集的总和 take-boolean数组检查元素 是否考虑和划分 K-需要的分区数 N-数组中元素的总数 curIdx-当前子板块指数 limitIdx-数组元素应位于的位置的lastIdx 上当*/ bool isKPartitionPossibleRec(内部arr[],内部子项目[],bool Take[], 整数子集,整数K,整数N,整数curIdx,整数limitIdx) { if(subsetSum[curIdx]==子集) { /*当前索引(K-2)表示相等的(K-1)子集 sum last partition已保留sum“subset”*/ if(curIdx==K-2) 返回true; //对下一个子集的递归调用 返回isKPartitionPossibleRec(arr、子项、已取、子项、, K、 N,curIdx+1,N-1); } //从limitIdx开始,将元素包含到当前分区中 对于(int i=limitIdx;i>=0;i--) { //如果已拍摄,请继续 如果(采取[i]) 继续; int tmp=子系统[curIdx]+arr[i]; //如果temp小于subset,则仅包含元素 //并递归调用
如果(tmp你确实意识到这个问题是NP难的。在动态规划中,划分为2有一个简单的伪多项式时间算法,但显然,因为对于k=2,一般情况下是NP难的,所以这个问题也是。我的问题是,当数组是
4,4,1,3,2,3,2,1
时,该算法试图通过添加ng
1+2+2
然后,
3+3
3+1
等等。它没有得到分区,最后将其解为[[4,1],[4,1],[3,2],[3,2]]。我不确定该算法如何找到替代方案?什么是“没有得到分区”意思是?@j_random_hacker我的意思是当数组
4,4,1,3,2,2,1
时,它尝试[[2,2,1][4,1]],这不是等和的K次分区。我还是不太明白你的意思…是[[2,2,1],[4,1]]它的第一次尝试?毫不奇怪,这第一次尝试不是一个有效的解决方案;像这样的回溯算法的整个设计是不断尝试解决方案,直到找到一个有效的解决方案。这可能需要很长时间。你知道这个问题是NP难的。划分为2在动态p中有一个简单的伪多项式时间算法程序设计没有考虑k。但是很明显,因为对于k=2,一般情况是np难的,所以这个问题也是。我的问题是,当数组是
4,4,1,3,2,3,2,1
时,算法试图通过添加
1+2+2
然后,
3+3
3+1
等等来解决它。它没有得到分区,最后是我不知道这个算法是如何找到替代方案的?什么是“没有得到分区”的意思?@j_random_hacker我的意思是当数组
4,4,1,3,2,2,1
,它尝试[[2,2,1][4,1]],这不是等和的K次分区。我还是不明白你的意思…是什么[[2,2,1],[4,1]]它的第一次尝试?毫不奇怪,这第一次尝试不是一个有效的解决方案;像这样的回溯算法的整个设计是不断尝试解决方案,直到找到一个有效的解决方案。这可能需要很长时间。
// 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";
}