在c ++中实现组合算法("把苹果放在不同的盘子里#34;)

时间:2014-06-27 19:10:44

标签: algorithm combinatorics

我生成了一组n元素数组,它们由交替的1和-1组成,后跟零,都以1开头。

例如,对于n = 5,数组是: 10000, 1-1000, 1-1100, 10年1月11日, 11年1月11日,

我需要在每个数组的非零数字之间“插入”零: 对于上例中的1-1100,枚举为:

1 -1 1 0 0,(允许一些1和-1之间没有0。)

1 -1 0 1 0,

1 0 -1 1 0,

1 0 -1 0 1,

1 0 0 -1 1,

1 -1 0 0 1(第一个元素仍需要为1)

是否有一个很好的算法来为具有上述格式的给定数组生成这样的枚举?

我认为问题就像将相同的苹果放入不同的盘子中一样(因为将零放入不同的间隙会产生不同的枚举)并允许一些盘子保持空白。

我需要打印出所有可能性,而不仅仅是计算它们。但目前我无法找到一个好办法。

1 个答案:

答案 0 :(得分:0)

这比看上去简单。

第一个元素总是1.因此,我们可以忽略它,而且只是 在我们的答案前加1。

在初始1之后的非零元素总是-1,1,-1等。 由于此模式已修复,我们可以将所有非零替换为1,然后 转回来。

所以现在我们只有一个0和1的列表,需要生成所有的 排列。

将所有内容放在Python中:

#!/usr/bin/env python3

N = 5

def main():
    # k = number of nonzeros, minus the initial one that's always there
    for k in range(N):
        seq = [0] * (N - 1 - k) + [1] * k
        for p in next_permutation(seq):
            result = decorate(p)
            print(" ".join("{:2d}".format(i) for i in result))

# adapted from http://stackoverflow.com/questions/4250125
def next_permutation(seq):
    seq = seq[:]
    first = 0
    last = len(seq)
    yield seq

    if last == 1:
        raise StopIteration

    while True:
        next = last - 1
        while True:
            next1 = next
            next -= 1
            if seq[next] < seq[next1]:
                mid = last - 1
                while seq[next] >= seq[mid]:
                    mid -= 1
                seq[next], seq[mid] = seq[mid], seq[next]
                seq = seq[:next1] + list(reversed(seq[next1:last])) + seq[last:]
                yield seq[:]
                break
            if next == first:
                raise StopIteration
    raise StopIteration

def decorate(seq):
    # Convert 1's to alternating -1, 1, then prepend a 1 to whole thing
    seq = seq[:]
    n = -1
    for i in range(len(seq)):
        if seq[i]:
            seq[i] = n
            n = -n
    return [1] + seq

main()