/ Algorithms

Knapsack Problem Step by Step

| | Algorithms

There are N{N} items, numbered 1,2,...,N{1, 2, ..., N}. For each index 1iN{1 \le i \le N}.

Item i{i} has a weight of wi{w_i}​ and a value of vi{v_i}.

James has decided to choose some of the N{N} items and carry them home in a knapsack. The capacity of the knapsack is T{T}, which means that the sum of the weights of items taken must be at most T{T}.

Find the maximum possible sum of the values of items that James can take home.

Constraints

All values in input are integers.

1N100{1 \le N \le 100}

1T105{1 \le T \le 105}

1wiW{1 \le w_i​ \le W}

1vi10{1 \le v_i​ \le 10}

Solution

Given the following capacity T{T}, N{N} items denoted by weights W{W} and item values V{V}.

capacity = 5
weight = [1, 2, 3]
items = [6, 10, 12]

For the table columns, we are increasing capacity from 0 to W{W}, where W{W} 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.

WV012345
00000000
160-----
2100-----
3120-----

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.

WV012345
00000000
16066666
2100-----
3120-----

For second row, now weight is 2, we can fill values same as row above it up to capacity 2.

For capacity 2 (w2{w_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 i{i} is the current row index. If we include then value would be:

Vi+F(Wi,CiWi)=10+F(Wi,CiW)=10+0=10{V_i + F(W_i, C_i - Wi) = 10 + F(W_i, C_i - W) = 10 + 0 = 10}

The max is 10 so result is 10. Now, the FF function is:

Previous item (Wi{W_i}) and (Wi{W_i}) = 0.

Iterations

If we walk through each iteration step by step we can see this in action. We may use M{M} as the memoization table symbol.

Miw=max(){M_{iw} = max()}

First

WV012345
00000000
16066666
21001016161616
3120-----

Finally, we reach the last row:

WV012345
00000000
16066666
21001016161616
3120610161822

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