以下Knapsack填充算法的实现有什么问题?

时间:2013-11-22 17:36:47

标签: python algorithm knapsack-problem

编辑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

所以现在我想问题是我的背包问题解决方案有什么问题?对于非常大的数字集,它是否效率低下且无法使用?如果这不是解决此类问题的正确位置,请告诉我。

3 个答案:

答案 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 * targetmax(items) < target,则会导致无限递归。