给定多个项目( 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]
我实施了一个生成所有排列的暴力方法,然后检查列表是否符合上述要求,但有更有效的方法吗?
答案 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
是一种优化,因为尝试任何大于新总数的整数都是毫无意义的。