如何从背包DP矩阵推导出所有解决方案

时间:2015-05-31 05:46:32

标签: python algorithm dynamic-programming knapsack-problem

我正在研究DP解决方案以解决背包问题。拥有一个具有权重和值的项目列表,我需要找到最大总值小于某个预定义权重的项目。没什么特别的,只有0-1 knapsack

我使用DP生成矩阵:

def getKnapsackTable(items, limit):
    matrix = [[0 for w in range(limit + 1)] for j in xrange(len(items) + 1)]
    for j in xrange(1, len(items) + 1):
        item, wt, val = items[j-1]
        for w in xrange(1, limit + 1):
            if wt > w:
                matrix[j][w] = matrix[j-1][w]
            else:
                matrix[j][w] = max(matrix[j-1][w], matrix[j-1][w-wt] + val)

    return matrix

其中items是元组(name, weight, value)的列表。现在有一个DP矩阵,他的最大可能值是右下位置的数字。我还可以回溯矩阵以找到提供最佳解决方案的项目列表。

def getItems(matrix, items):
    result = []
    I, j = len(matrix) - 1, len(matrix[0]) - 1
    for i in range(I, 0, -1):
        if matrix[i][j] != matrix[i-1][j]:
            item, weight, value = items[i - 1]
            result.append(items[i - 1])
            j -= weight

    return result

很好,现在我可以得到结果:

items = [('first', 1, 1), ('second', 3, 8), ('third', 2, 5), ('forth', 1, 1), ('fifth', 1, 2), ('sixth', 5, 9)]
matrix = getKnapsackTable(items, 7)
print getItems(matrix, items)

并会看到:[('fifth', 1, 2), ('third', 2, 5), ('second', 3, 8), ('first', 1, 1)]

问题是这不是一个独特的解决方案。我可以使用'first'元素(这是完全相同的,但有时解决方案可能不同),而不是'forth'元素。我试图弄清楚如何获得所有解决方案,而不仅仅是一个。我意识到需要更多时间,但我对此感到满意。

1 个答案:

答案 0 :(得分:1)

您可以照常计算原始DP矩阵(即使用DP),但要查找从最终状态返回矩阵时需要递归的所有最佳解法。这是因为矩阵中的任何给定状态(i,j)至少有一个最佳前趋状态,但它可能有两个:它可能是状态的最大值(i, j)可以通过选择将项i添加到状态(i-1,jw(i))的最优解,或者通过将项i输出并且仅保持(i-1,j)的最优解来实现。当这两个选择产生相等的总值时,即

时,就会发生这种情况
matrix[i-1][j] == matrix[i-1][j-w(i)]+v(i),

其中w(i)和v(i)分别是对象i的权重和值。无论何时检测到这样的分支,都需要遵循每个分支。

请注意,可能存在极大数量的最佳解决方案:例如,考虑所有项目都具有权重1的情况。在这种情况下,所有(n选择w)解决方案都是最佳的。