Reputation: 222581
I am working on DP solution for a knapsack problem. Having a list of items with their weights and value, I need to find the items with the maximum total value less then some predefined weight. Nothing special, just 0-1 knapsack.
I use DP to generate a matrix:
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
where items are a list of tuples (name, weight, value)
. Now having a DP matrix, he maximum possible value is the number in the right down position. I can also backtrack the matrix to find the list of items that gives the best solution.
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
Great, now I can get the results:
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)
and will see: [('fifth', 1, 2), ('third', 2, 5), ('second', 3, 8), ('first', 1, 1)]
.
The problem is that this is not a unique solution. Instead of the 'first'
element, I can take the 'forth'
element (which is absolutely the same, but sometimes the solutions can be different). I am trying to figure out how to get all the solutions instead of just one. I realize that it will take more time, but I am ok with that.
Upvotes: 5
Views: 2097
Reputation: 51226
You can compute the original DP matrix as usual (i.e., using DP), but to find all optimal solutions you need to recurse as you travel back through the matrix from the final state. That's because any given state (i, j) in your matrix has at least one optimal predecessor state, but it might have two: it might be that the maximum value for state (i, j) can be achieved either by choosing to add item i to the optimal solution for state (i-1, j-w(i)), or by leaving item i out and just keeping the optimal solution for (i-1, j). This occurs exactly when these two choices yield equal total values, i.e., when
matrix[i-1][j] == matrix[i-1][j-w(i)]+v(i),
where w(i) and v(i) are the weight and value of object i, respectively. Whenever you detect such a branching, you need to follow each branch.
Note that there could be an extremely large number of optimal solutions: e.g., consider the case when all items have weight 1. In this case, all (n choose w) solutions are optimal.
Upvotes: 2