编辑2:现在测试失败({64,1,36,81},82)
修改1:现在已更新以解决由于delta>而导致的问题MAX(项目)
Edit0:现在更新以修复由于振荡增量问题导致的无限递归。
在this算法视频中(大约2:52),Skiena教授指出背包问题如下......
背包问题:给定一组整数S = {s1,s2,...,sN}并给定目标数T找到一个S的子集,它将完全相加到T。
然后他继续说这是其中没有已知有效解决方案的问题之一!
但是无论如何我试过了,这是我尝试解决的问题(这似乎适用于我尝试过的数字)......
from itertools import accumulate
#items - All available items
#target - The size of the knapsack
#returns - A subset of {items} whose sum adds upto target
# if possible else returns None
def KnapsackItems(items, target):
s = sum(items)
if s < target:
return None
delta = s - target
if delta == 0:
return items
if delta in items:
result = items - {delta}
return result
if delta > max(items):
sortedItems = list(sorted(items))
deltas = list(map(lambda x: x - target, accumulate(sortedItems)))
ul = [i for i,d in zip(sortedItems, deltas) if d <= i]
return KnapsackItems(set(ul), target)
else:
U = {i for i in items if i < delta}
V = KnapsackItems(U, delta)
if V:
result = items - V
return result
return None
这是测试工具......
def test(items, target):
print("Items:", items)
print("Target:", target)
result = KnapsackItems(items, target)
if result and not sum(result) == target:
print("Result:", result)
print("FAIL: sum of returned set does not match target ({})".format(target))
elif result:
print("Result:", result)
print("Success (sum of returned set:{})".format(sum(result)))
else:
print("No solution could be found")
视频中的示例...
test({1,2,5,9,10}, 22)
test({1,2,5,9,10}, 23) #No solution expected
test({1,2,3,4,5}, 11)
test({1,2}, 2)
test({4,3,2}, 5)
test({1, 3, 4, 7, 9}, 13)
test({6,7,8,3,14,5,15,2,4}, 29)
test({1,2,3,4,5,6,7},14)
test({64, 1, 36, 81}, 82)
结果...
Items: {9, 10, 2, 5, 1}
Target: 22
Result: {9, 10, 2, 1}
Success (sum of returned set:22)
Items: {9, 10, 2, 5, 1}
Target: 23
No solution could be found
Items: {1, 2, 3, 4, 5}
Target: 11
Result: {1, 2, 3, 5}
Success (sum of returned set:11)
Items: {1, 2}
Target: 2
Result: {2}
Success (sum of returned set:2)
Items: {2, 3, 4}
Target: 5
Result: {2, 3}
Success (sum of returned set:5)
Items: {9, 3, 4, 1, 7}
Target: 13
Result: {9, 4}
Success (sum of returned set:13)
Items: {2, 3, 4, 5, 6, 7, 8, 14, 15}
Target: 29
Result: {14, 15}
Success (sum of returned set:29)
Items: {1, 2, 3, 4, 5, 6, 7}
Target: 14
Result: {2, 5, 7}
Success (sum of returned set:14)
Items: {64, 81, 36, 1}
Target: 82
No solution could be found
所以现在我想问题是我的背包问题解决方案有什么问题?对于非常大的数字集,它是否效率低下且无法使用?如果这不是解决此类问题的正确位置,请告诉我。
答案 0 :(得分:2)
当max(items) < target < sum - max(items)
(我不知道Python)时,delta
将始终超过max(items)
并且在递归检查之前不会删除任何项目,并且算法永远不会终止。
编辑版:
当max(items)
无法成为解决方案的一部分时(例如max(items) > target
}和max(items) < delta
时,它现在失败了。示例:{2, 3, 4, 6}, 5
。第一次迭代后,它变为{2, 3, 4}, 10
,返回None
,导致顶级调用返回None
,这是不正确的。
答案 1 :(得分:1)
KnapsackItems({6,7,8,3,14,5,15,2,4}, 29)
File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 95, in KnapsackItems
File "C:\Program Files (x86)\Wing IDE 101 4.1\src\debug\tserver\_sandbox.py", line 95, in <setcomp>
builtins.RuntimeError: maximum recursion depth excee
显然,100万美元的问题并不容易解决:)
答案 2 :(得分:1)
有可能无限递归,如下面的数据集。
For example,
{(1,2,3,4,5,6,7),14}
sum = 28.
delta = 14.
因此,如果sum = 2 * target
和max(items) < target
,则会导致无限递归。