【问题标题】:Splitting a group of numbers into a subgroups of members将一组数字拆分为成员的子组
【发布时间】:2017-03-21 19:39:56
【问题描述】:

我想问如何检查一组数字是否可以分成子组(每个子组必须有 3 个成员),每个子组成员的总和是否相等。这么多组合怎么查?

例子:

int numbers[] = {1, 2, 5, 6, 8, 3, 2, 4, 5};

可以分为

{1, 5, 6}, {2, 8, 2}, {3, 4, 5}

【问题讨论】:

  • 在所有情况下,您的子组是否应该始终只有 3 个成员?即使一开始你有 15000 个号码?

标签: c++


【解决方案1】:

可以遵循递归方法,其中一个保留两个数组:

  • 包含每个子组总和的数组。
  • 一个布尔数组,用于检查一个元素是否已被纳入 是否有某个子组。

您在本文的其余部分中要求了 3 个子组,即 K = 3,但请记住,在处理递归时,应考虑基本情况。在这种情况下,我们将重点关注两个基本情况:

  1. 如果 K 为 1,那么我们已经有了答案,完整数组只有 总和相同的子集。
  2. 如果 N

如果group的和不能被K整除,那么它就不能整除。只有当 k 除以总和时,我们才会继续。我们的目标简化为将组划分为 K 个子组,其中每个子组的总和应该是该组的总和除以 K。

在下面的代码中,编写了一个递归方法,它试图将数组元素添加到某个子集中。如果这个子集的总和达到要求的总和,我们递归地迭代下一部分,否则我们回溯不同的元素集。如果总和达到所需总和的子集数量为(K-1),我们标记可以将数组划分为等和的 K 个部分,因为剩余元素的总和已经等于所需总和。

引用自 here,而在您的情况下,您将设置 K = 3,如示例代码中所示。

// C++ program to check whether an array can be
// subsetitioned 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 subsetition or not
    K               - number of subsetitions 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 subsetition 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 subsetition
    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 subsetition 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 subsetitioned 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 subsetitions 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 subsetitions
    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;
    if (subset < subsetSum[0])
        return false;

    //  call recursive method to check K-subsetition 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";
}

输出:

等分是可能的。


相关链接:23

【讨论】:

    【解决方案2】:

    在这种特殊情况下(3x3)你可以做类似的事情:

    const int COUNT = 9;
    bool test(int const (&array)[COUNT], std::vector<std::vector<int>>* result) {
    
        for(int _1=0; _1<COUNT-2; ++_1) {
            for(int _2=1; _2<COUNT-1; ++_2) {
                if(_2 == _1)
                    continue;
                for(int _3=2; _3<COUNT; ++_3) {
                    if(_3 == _2 || _3 == _1)
                        continue;
                    std::vector<int> chosen1 {array[_1], array[_2], array[_3]};
                    std::vector<int> rest;
                    for(int _x = 0; _x < COUNT; ++_x) {
                        if(_x != _1 && _x != _2 && _x != _3) {
                            rest.push_back(array[_x]);
                        }
                    }
    
                    for (int _4 = 0; _4 < COUNT-5; ++_4) {
                        for (int _5 = 1; _5 < COUNT-4; ++_5) {
                            if(_5 == _4)
                                continue;
                            for (int _6 = 2; _6 < COUNT-3; ++_6) {
                                if(_6 == _5 || _6 == _4)
                                    continue;
                                std::vector<int> chosen2 = {rest[_4], rest[_5], rest[_6]};
                                std::vector<int> chosen3;
                                for(int _x = 0; _x < COUNT-3; ++_x) {
                                    if(_x != _4 && _x != _5 && _x != _6) {
                                        chosen3.push_back(rest[_x]);
                                    }
                                }
    
                                int total = std::accumulate(chosen1.begin(), chosen1.end(), 0);
    
                                if((std::accumulate(chosen2.begin(), chosen2.end(), 0) == total) &&
                                   (std::accumulate(chosen3.begin(), chosen3.end(), 0) == total)) {
                                    *result = {chosen1, chosen2, chosen3};
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }
    
    int main() {
        int values[] = {1, 2, 5, 6, 8, 3, 2, 4, 5};
        std::vector<std::vector<int>> result;
        if(test(values, &result)) {
            for(auto& x : result) {
                std::cout << "{";
                for(auto& y : x) {
                    std::cout << y << ",";
                }
                std::cout << "}";
            }
            std::cout << std::endl;
        } else {
            std::cout << "not found";
        }
    }
    

    如果您有更长的数组 (3+ * 3),那么您可以使用递归(您也可以在我的示例中使用它),但这仍然会很慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多