找到与索引相乘时总和为N的所有组合

时间:2016-09-04 01:28:48

标签: python algorithm permutation combinatorics

给定多个项目( n ),生成所有可能列表的最有效方法是什么[a 1 2 ,..., n ]非负整数,条件是:

1 * a 1 + 2 * a 2 + 3 * a 3 + ... + n * a n = n

使用Python?

因此,例如,给定n为5,以下组合为:

[0,0,0,0,1]

[1,0,0,1,0]

[0,1,1,0,0]

[2,0,1,0,0]

[1,2,0,0,0]

[3,1,0,0,0]

[5,0,0,0,0]

我实施了一个生成所有排列的暴力方法,然后检查列表是否符合上述要求,但有更有效的方法吗?

1 个答案:

答案 0 :(得分:2)

A"贪心"算法适用于此。我在这里使用Python 3:

def pick(total):

    def inner(highest, total):
        if total == 0:
            yield result
            return
        if highest == 1:
            result[0] = total
            yield result
            result[0] = 0
            return
        for i in reversed(range(total // highest + 1)):
            result[highest - 1] = i
            newtotal = total - i * highest
            yield from inner(min(highest - 1, newtotal),
                             newtotal)

    result = [0] * total
    yield from inner(total, total)

然后,例如,

for x in pick(5):
    print(x)

显示:

[0, 0, 0, 0, 1]
[1, 0, 0, 1, 0]
[0, 1, 1, 0, 0]
[2, 0, 1, 0, 0]
[1, 2, 0, 0, 0]
[3, 1, 0, 0, 0]
[5, 0, 0, 0, 0]

与大多数递归算法一样,它会做一个或多或少的显而易见的事情,然后通过递归来解决剩下的(子)问题。

此处inner(highest, total)表示使用不大于total的整数查找highest的所有分解。我们可以使用多少份highest?不那么明显的答案是我们可以使用0,1,2,......,最多(和包括)total // highest个副本,但不能超过这个。除非highest为1,否则我们必须使用1个total副本。

然而,我们使用highest的许多副本,剩下的子问题是使用不大于highest - 1的整数来分解总数的剩余部分。传递min(highest - 1, newtotal)代替highest - 1是一种优化,因为尝试任何大于新总数的整数都是毫无意义的。