【问题标题】:Combinatorial Optimisation with 0 and 10 和 1 的组合优化
【发布时间】:2014-03-29 22:10:15
【问题描述】:

我正在努力解决这个问题: 给定 0 和 1 的数量,生成包含 0 和 1 的所有可能组合的列表。

例子:如果我们有一个1和两个0,算法会返回

 001
 010
 100

问题在于经典的组合算法没有为此目的进行优化。 这是非优化组合算法将返回的结果:

001
001
010
010
100
100

如您所见,所有组合都重复了两次,因为 0 被解释为不同的元素。

如何在不重复组合的情况下,生成输入 0 和 1 的数量的可能组合列表?

PS : 这将在 Javascript 中使用

编辑:已解决!使用@Batch 方法。

function combin(o, i)
{
    if (o == 0 && i > 0) 
    {
        for (var j = 0, s = ''; j < i; j++)
        {
            s += '1';
        }
        return [s];
    } 
    else if (i == 0 && o > 0)
    {
        for (var j = 0, s = ''; j < o; j++)
        {
            s += '0';
        }
        return [s];
    } 
    else if (i == 0 && 0 == o)
    {
        return [''];
    } 
    else if (i > 0 && o > 0)
    {
        var l = combin(o - 1, i);
        for (var j in l)
        {
            l[j] = '0' + l[j];
        }
        var k = combin(o, i-1);
        for (var j in k)
        {
            k[j] = '1' + k[j];
        }
        return l.concat(k);
    }
}

【问题讨论】:

  • 这些并不是所有可能的组合。
  • @Oriol 否,因为它两次给出相同的组合。看:jsfiddle.net/FkT2n
  • @Oriol 否,因为我想生成严格数量为 0 和 1 的组合。我不想要包含 0 和 1 的所有组合。我需要所有恰好具有 x 0 的组合例如,恰好 y 1。
  • 为了帮助人们帮助你,编辑帖子并复制/粘贴源代码。

标签: javascript algorithm combinatorics


【解决方案1】:

这里有一种方法:从将所有 0 放在前面的字符串开始。现在将最右边的 0 移到最后。然后,将第二个最右边的 0 向右移动一个位置,将最后一个 0 放在它旁边。同样,将最右边的 0 移到最后。将第二个最右边的 0 再右移一步,将最右边的 0 再次放在它旁边,shift shift shift。一旦你移动了最右边的两个 0 对,开始移动第三个最右边的 0.... 你得到了图片。

示例:三个 0,三个 1:

000111
001011
001101
001110
010011
010101
010110
011001
011010
011100
100011
100101
100110
101001
101010
101100
110001
110010
110100
111000

不知道如何为此编写一个漂亮的循环,但一旦你掌握了这个想法,你就可以四处玩弄,如果你愿意的话,试着找出一个。也许你可以找到一个漂亮的递归,但现在想不出这个方法。


更优雅的方法如下;请注意,使用n 0s 和m 1s 生成所有字符串的方法是:

字符串以 0 开头,附加从 n-1 0s 和 m 1s 生成字符串的所有组合,或者以 1 开始字符串并附加从 n 0s 和 m-1 生成字符串的所有组合1秒。生成的字符串集是不相交的,所以一个简单的递归就可以了,不用担心需要多次生成字符串。如果您愿意,您也可以迭代地进行(迭代生成的字符串的长度,对于迭代 i,保持不使用 0、使用一个 0、...、使用 i 0 等的集合)

总而言之,递归似乎是我的最佳选择。基本情况很简单:如果 n = 0,你能得到的唯一字符串是 1^m,如果 m = 0,你能得到的唯一字符串是 0^n(其中 ^ 表示重复)。


如果您想实现该递归以及测试它的方法(在某种程度上),请注意您可以生成的字符串数量为n + m 选择n = n + m 选择m,所以计算你得到的字符串的数量会给你一个提示,你正在做的事情是否按预期工作。不确定 javascript 是否可以轻松访问二项式系数。

【讨论】:

  • 你可能想要使用记忆,所以如果不需要的话你不会重新计算集合。例如,如果您计算其中包含五个 0 和五个 1 的字符串,如果您不存储结果并重用它,您最终会在递归树的许多子树中计算包含三个 0 和三个 1 的字符串;如果您在获得结果后存储结果,则可以避免这种情况。这需要一些会计,所以相关的建议可能更简洁。
【解决方案2】:

我假设您想快速完成此操作。如果您将 0/1 模式表示为整数位,则最小的位是“0...01..1”,例如0001111 如果您有 3 个 0 位和 4 个 1 位 - 并且最大整数是“1..10..0”。 (例如 1111000 )。

然后,您的问题是生成按字典顺序排列的下一位排列(即具有相同 1 位数的下一个整数)的已知问题。

使用来自http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation 的代码的简单实现如下(伪代码):

v = '0..01..1'b  // Initialize t as smallest integer of the pattern
while ( t <= '1..10..0'b ):
    t = (v | (v - 1)) + 1
    v = t | ((((t & -t) / (v & -v)) >> 1) - 1)
    print v

请参阅http://www.geeksforgeeks.org/next-higher-number-with-same-number-of-set-bits/ 和其中的参考资料,了解有关算法工作原理的更详细说明。

【讨论】:

  • 这是一个有趣的方法,但我不确定它是否适用于 Javascript。
  • w 和 t 末尾的“b”是什么意思? v是什么?
  • b 表示它是整数的二进制表示,您需要使用简单的辅助函数来完成。 v/w 混淆是一个错字,我已经修正了。
猜你喜欢
  • 1970-01-01
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多