【问题标题】:Algorithm that can create all combinations and all groups of those combinations可以创建所有组合以及这些组合的所有组的算法
【发布时间】:2016-08-24 14:53:29
【问题描述】:

假设我有一组元素S = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }

我想创建 3 的组合并将它们分组,以使没有数字出现在多个组合中。

这是一个例子: { {3, 7, 9}, {1, 2, 4}, {5, 6, 8} }

组中数字的顺序无关紧要,整个示例中组的顺序也不重要。

简而言之,我想要原始集合中每个可能的组合中的每个可能的组组合,不包括在多个组中出现数字的组合。

我的问题:这在运行时间和内存方面真的可行吗?我的样本量可能在 30-50 个左右。

如果是这样,创建此算法的最佳方法是什么?是否最好创建所有可能的组合,并仅在数字尚未出现时才选择组?

我在 Qt 5.6 中编写此代码,这是一个基于 C++ 的框架。

【问题讨论】:

  • {4, 7, 9} AND {1, 2, 4} 出现 4 正常吗?
  • 哇今天不是我的日子。它不应该是。我会解决的。
  • @Dillydill123:基于m69的正确算法,k组的公式为3k-1*3k-2*3k-4*3k-5*...*1/2**k。换句话说,从 1 到 3k 的所有非 0 mod 3 的数字的乘积除以 2 的 k 次方。我是用python计算的。
  • 短公式:(3k)! / (k! * 6^k)
  • 输出大小为this sequence。 30 个元素是完全不可行的。

标签: c++ algorithm combinations


【解决方案1】:

您可以递归地执行此操作,并避免重复,如果您在每次递归中保持第一个元素固定,并且仅按顺序将值分组为 3,例如:

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

将最低的元素放在第一个位置(a),并保持在那里:

{a,b,c} = {1, *, *}

对于第二个点 (b),遍历从第二低到第二高的每个值:

{a,b,c} = {1, 2~8, *}

对于第三个点 (c),遍历每个高于第二个值的值:

{1, 2~8, b+1~9}

然后用其余的值递归。

{1,2,3} {4,5,6} {7,8,9}
{1,2,3} {4,5,7} {6,8,9}
{1,2,3} {4,5,8} {6,7,9}
{1,2,3} {4,5,9} {6,7,8}
{1,2,3} {4,6,7} {5,8,9}
{1,2,3} {4,6,8} {5,7,9}
{1,2,3} {4,6,9} {5,7,8}
{1,2,3} {4,7,8} {5,6,9}
{1,2,3} {4,7,9} {5,6,8}
{1,2,3} {4,8,9} {5,6,7}
{1,2,4} {3,5,6} {7,8,9}
...
{1,8,9} {2,6,7} {3,4,5}

我说“按顺序”,不一定是任何特定的顺序(数字、字母...),它可以是输入的原始顺序。如果您确保按照收到的顺序将其余值传递给下一个递归,则可以避免重新排序每个递归的输入。


递归的遍历:

假设您得到输入 {1,2,3,4,5,6,7,8,9}。作为组中的第一个元素,您从输入中获取第一个元素,对于其他两个元素,您遍历其他值:

{1,2,3}
{1,2,4}
{1,2,5}
{1,2,6}
{1,2,7}
{1,2,8}
{1,2,9}
{1,3,4}
{1,3,5}
{1,3,6}
...
{1,8,9}

确保第三个元素总是在第二个元素之后,以避免重复,例如:

{1,3,5} ⇆ {1,5,3}

现在,假设在某个时刻,您选择了它作为第一组:

{1,3,7}

然后将其余的值传递给下一个递归:

{2,4,5,6,8,9}

在此递归中,您应用与第一个组相同的规则:将第一个元素作为组中的第一个元素并将其保留在那里,并迭代第二个和第三个元素的其他值:

{2,4,5}
{2,4,6}
{2,4,8}
{2,4,9}
{2,5,6}
{2,5,8}
{2,5,9}
{2,6,7}
...
{2,8,9}

现在,假设在某个时刻,您选择了它作为第二组:

{2,5,6}

然后将其余的值传递给下一个递归:

{4,8,9}

由于这是最后一组,所以只有一种可能性,所以这个特定的递归将以组合结束:

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

如您所见,您不必在任何时候对值进行排序,只要按照您收到它们的顺序将它们传递到下一个递归即可。因此,如果您收到例如:

{q,w,e,r,t,y,u,i,o}

然后你从这个组中选择:

{q,r,u}

那么你应该继续:

{w,e,t,y,i,o}


这是一个演示该方法的 JavaScript sn-p;它返回一个包含元素组组合的 3D 数组。
(过滤器函数创建输入数组的副本,删除了元素 0、i 和 j。)

function clone2D(array) {
    var clone = [];
    for (var i = 0; i < array.length; i++) clone.push(array[i].slice());
    return clone;
}

function groupThree(input) {
    var result = [], combination = [];
    group(input, 0);
    return result;

    function group(input, step) {
        combination[step] = [input[0]];
        for (var i = 1; i < input.length - 1; i++) {
            combination[step][1] = input[i];
            for (var j = i + 1; j < input.length; j++) {
                combination[step][2] = input[j];
                if (input.length > 3) {
                    var rest = input.filter(function(elem, index) {
                        return index && index != i && index != j;
                    });
                    group(rest, step + 1);
                }
                else result.push(clone2D(combination));
            }
        }
    }
}

var result = groupThree([1,2,3,4,5,6,7,8,9]);
for (var r in result) document.write(JSON.stringify(result[r]) + "<br>");

【讨论】:

  • 这看起来很有趣,可能正是我需要的。我注意到在您说“使用其余值递归”之后,您在第二组中有一个错误。数字 7 出现在多个组中。当您谈论点 (a) (b) 和 (c) 时,这些仅适用于第一组 3 个数字吗?另外,你能解释一下我如何用其余的值递归吗?我在这里看不到全貌
  • @Dillydill123 我已经在带有工作键盘的计算机上扩展了答案:-)
  • 感谢您非常深入的回答!不幸的是,由于我的样本量很大,创建所有组合是不可行的。不过我会接受你的回答!
  • 你能告诉我数组 g 的用途吗?我不熟悉 JavaScript,现在它看起来对我没有任何作用。
  • @Dillydill123 这是第一版代码的遗留物,我忘了删除它;对于那个很抱歉。我已经稍微修正了代码示例。
【解决方案2】:

对于 n 次取 3 件的事情,您可以使用 3 个嵌套循环:

    for(k = 0; k < n-2; k++){
        for(j = k+1; j < n-1; j++){
            for(i = j+1; i < n  ; i++){
                ...  S[k] ... S[j] ... S[i]
            }
        }
    }

对于一次取 k 个 n 事物的通用解决方案,您可以使用 k 个计数器的数组。

【讨论】:

    【解决方案3】:

    我认为您可以通过使用动态编程的硬币找零问题来解决它,只需假设您正在寻找 3 的变化并且数组中的每个索引都是硬币值 1,然后只需输出具有的硬币(您的数组中的值)被发现。 链接:https://www.youtube.com/watch?v=18NVyOI_690

    【讨论】:

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