There are items, numbered . For each index .
Item has a weight of and a value of .
James has decided to choose some of the items and carry them home in a knapsack. The capacity of the knapsack is , which means that the sum of the weights of items taken must be at most .
Find the maximum possible sum of the values of items that James can take home.
Constraints
All values in input are integers.
Solution
Given the following capacity , items denoted by weights and item values .
capacity = 5
weight = [1, 2, 3]
items = [6, 10, 12]
For the table columns, we are increasing capacity from 0 to , where is 5. This gives us a range of 0 to 5; the max capacity.
On each row, we must consider the items, we have denoted the weights and values. For each row, we are really only considering items calculated in previous rows and for each column we consider for that much capacity.
The initial starting point is for 0 weight (no item) the value is 0 regardless of capacity and similarly if we have 0 capacity then we cannot put any item so value would be 0.
We end up with the following memoization table.
W | V | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 6 | 0 | - | - | - | - | - |
2 | 10 | 0 | - | - | - | - | - |
3 | 12 | 0 | - | - | - | - | - |
The first row (row with weight 1) is simple as we have weight 1, so we can fill its value from capacity 1. Since it is a single item, the entire row would have value 6.
W | V | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 6 | 0 | 6 | 6 | 6 | 6 | 6 |
2 | 10 | 0 | - | - | - | - | - |
3 | 12 | 0 | - | - | - | - | - |
For second row, now weight is 2, we can fill values same as row above it up to capacity 2.
For capacity 2 (), there are two choice:
- Include the current item
- Exclude the current item
If we exclude current item then value would be same as top row 6. Where is the current row index. If we include then value would be:
The max is 10 so result is 10. Now, the function is:
Previous item () and () = 0.
Iterations
If we walk through each iteration step by step we can see this in action. We may use as the memoization table symbol.
First
W | V | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 6 | 0 | 6 | 6 | 6 | 6 | 6 |
2 | 10 | 0 | 10 | 16 | 16 | 16 | 16 |
3 | 12 | 0 | - | - | - | - | - |
Finally, we reach the last row:
W | V | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 6 | 0 | 6 | 6 | 6 | 6 | 6 |
2 | 10 | 0 | 10 | 16 | 16 | 16 | 16 |
3 | 12 | 0 | 6 | 10 | 16 | 18 | 22 |
Code
Iteration
...
def knapsack_i(capacity: int, weights, values):
memo = [[0 for i in range(capacity + 1)] for i in range(len(weights) + 1)]
memo[1] = [values[0]] * (capacity + 1)
for row in range(len(weights)):
for w in range(capacity + 1):
if weights[row] <= w:
print(f"Current row weight does not exceed current capacity (column)")
current_row_current_weight = memo[row][w]
current_row_previous_weight = memo[row][w - weights[row]] + values[row]
include = max(current_row_current_weight, current_row_previous_weight)
memo[row + 1][w] = include
else:
print(f"Current row weight exceeds current capacity (column)")
print(f"Weight: {weights[row]} is greater than {w}")
print(f"Setting next row value: {memo[row][w]}")
memo[row + 1][w] = memo[row][w]
return memo[-1][-1]
if __name__ == "__main__":
assert knapsack_i(5, [1, 2, 3], [6, 10, 12]) == 22