Definition
Knapsack Problem
Knapsack Problem
The Knapsack problem is a problem that asks for filling a fixed-size knapsack with items that have a size and a value such that the total value of the knapsack is maximised. Greedy algorithms on the value of the elements won’t work here.
The Knapsack problem is an optimisation problem is about maximising
whereby
where
, is the value and of item , is the maximum weight capacity of the knapsack, and
Approaches
Naive Enumeration
Time Complexity:

Branch and Bound
Branch and bound is used here to omit certain subtrees in search space that are not expected to increase the current optimum under the assumption of monotonicity.

If

Example: Given
| Item | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| Weight | 32 | 16 | 21 | 50 |
| Value | 80 | 20 | 63 | 100 |
| Coefficient | 2.5 | 1.25 | 3 | 2 |
Order the items according to their coefficients:
- Item
with - Item
with - Item
with - Item
with
Enumerate
- Select
given that . (total weight for current enumeration) (rest capacity for current enumeration)
- Select
given that - Can’t selected
given that : (remains the same) (remains the same) (remains the same)
- Select
given that (remains the same) (remains the same) (remains the same)
- Effects:
(best solution so far) (best solution so far)
Observation
As soon as the first item
is found that does not fit inside the knapsack in the current enumeration, i.e. , the current capacity , the rest capacity , and the upper bound are fixed. After that, only the lower bound could be adjusted, where possible.
Enumerate: What if
- This is equivalent to the enumeration
above. Thus: - Effects:
Enumerate: What if
- This is equivalent to the enumeration
above. Thus: - Effects:
Enumerate: What if
- This is the first occurrence that differs from the enumerations above since
were not chosen since it didn’t fit into the Knapsack’s capacity. - Therefore, this state (and its subsequent subspace) can be ignored.
Enumerate: What if
- In the first enumeration, we tried to put
into the Knapsack’s upper boundary. Now, we don’t put into the knapsack at all. Thus: - Effects:
(unchanged) (updated) (unchanged) (unchanged)
- Bound:
- Given that
, we already found the best solution in the current sub-state space. Further solutions in the current sub-state space don’t need to be explored.
- Given that
Enumerate: What if
- Select
given that . (total weight for current enumeration) (rest capacity for current enumeration)
- Next item would be
, however, we decided to omit it. - Select
given that - Select
given that - We do not add any fraction to
given that there are no more elements that could be added.
- Effects:
(updated) (unchanged)
- Bound:
- Again, given that
, we can bound here. There’s no better solution in the current sub-state space.
- Again, given that
Enumerate: What if
- First item would be
, however, we decided to omit it. - Select
given that : - Select
given that - Select
given that - Again, no fraction is added to
given that no further items are available to be selected.
- Effects:
(updated) (updated)
- Bound:
- Again, given that
, the best possible solution in the current sub-state space is found. No further exploration needed.
- Again, given that
The entire search space is now explored. The most optimal solution is:
( is omitted)

Dynamic Programming
The knapsack problem is a classic example for using dynamic programming for a problem. Given
| 0 | 1 | 2 | … | ||
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | … | 0 |
| 1 | … | ||||
| 2 | … | ||||
| … | … | … | … | … | … |
| … |
After the DP table is built, the algorithm just chooses based on the table dp[n][max_size].
TL;DR: Dynamic Programming Approach
The dynamic programming approach solves the problem for all
and , builds up a table and picks the solution for the desired problem. Solutions of smaller problems can be used for the next bigger problem, until the desired problem is picked.
Python:
def knapsack(max_size: int, items: list[tuple[int, int]]) -> int:
n: int = len(items)
dp: list[list[int]] = [
[0] * (max_size + 1)
for _ in range(n + 1)
]
for i in range(1, n + 1):
item_size, item_value = items[i - 1]
for w in range(max_size + 1):
if item_size <= w:
dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - item_size] + item_value)
else:
dp[i][w] = dp[i - 1][w]
return dp[n][max_size]