我有一个名称和数字的字典,范围从700到2500,我想将它们组合在一个新的列表中,其中组的总和不超过4500.然后我将选择最少量的一个条目。
我知道我可以列出所有可能的组合,然后删除超过4500的条目,但这会产生太多不可用的项目。
任何提示?
更新: 感谢@Andrea de Marco,我有一部分问题。
现在使用背包功能我有最好的条目,但并非所有条目都在列表中。所以我必须运行该函数n次,直到列表为空。
由于我没有对问题使用任何“值”,我将值设置为1。
答案 0 :(得分:1)
您在文献中的问题被称为背包问题
http://en.m.wikipedia.org/wiki/Knapsack_problem
http://rosettacode.org/wiki/Knapsack_problem/0-1
https://sites.google.com/site/mikescoderama/Home/0-1-knapsack-problem-in-p
答案 1 :(得分:0)
如果您想使用不同的项目组合,则需要itertools
。这将允许您生成所有可能的项目组合,而无需通过一次构建整个批次来实际填充内存。你可能会发现这个食谱很有用:
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
您可以使用它来生成词典中values()
的所有组合。
假设您希望尽可能接近某些target
但是尽可能少的值,您可以尝试:
best = None
for set_ in powerset(d.values()):
if best is None and sum(set_) <= target:
best = set_
elif (sum(best) < sum(set_) <= target or # closer or
(sum(best) == sum(set_) and # as close and
len(set_) < len(best))): # shorter
best = set_
然而,请注意,随着len(d.values())
越来越大,这种天真的蛮力方法非常缓慢;集合S
的powerset中的子集数量为2**n
,其中n == len(S)
。