Knapsack Variants
Overview
The knapsack problem models resource allocation with a capacity constraint. Given items, each with weight and value , and a knapsack with capacity , select items to maximise total value without exceeding capacity. Two variants are considered: the 0/1 knapsack (items cannot be split) and the fractional knapsack (items can be split arbitrarily).
The 0/1 variant requires dynamic programming; the fractional variant is solved greedily. Understanding why greedy works for one and not the other is a central lesson in algorithm design.
0/1 Knapsack (DP)
Each item is either taken in full or left behind. The DP recurrence:
Let be the maximum value achievable using items through with capacity :
The two choices at each step: exclude item (value unchanged, capacity unchanged), or include item (gain , consume of capacity).
Example
, items: , , .
DP table (rows = items considered, columns = capacity):
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
| 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | |
| 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | |
| 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 |
Optimal: take items 1 and 3, total weight , total value .
Complexity
Time: . Space: or with space optimisation (only previous row needed). This is pseudo-polynomial: polynomial in the numeric value , but not in the input size . If is large, the algorithm is impractical.
Fractional Knapsack (Greedy)
Items can be split arbitrarily. The greedy strategy:
- Compute value per unit weight: for each item.
- Sort items by this ratio (descending).
- Take as much as possible of the highest-ratio item; if capacity remains, move to the next.
sort items by v_i / w_i descending
total = 0
for each item (sorted):
if W >= w_i:
take all of item; W -= w_i; total += v_i
else:
take fraction W / w_i; total += (W / w_i) * v_i; break
Time: for sorting, for selection.
Example (Same Items)
, , . Capacity .
- Item 3: ratio 1.5, take all → value 3, capacity left 5.
- Item 1: ratio 1.33, take all → value 4, capacity left 2.
- Item 2: ratio 1.25, take → value 2.5.
Total: . (Compare 0/1 optimum: 7.)
Why Greedy Works for Fractional
The proof is straightforward: if any optimal solution does not fill capacity with the highest-ratio item first, we can exchange a lower-ratio item for an equal weight of the higher-ratio item and increase total value. So an optimal solution must greedily take the highest-ratio items.
Why Greedy Fails for 0/1
The all-or-nothing constraint is the culprit. A high-ratio item might be so heavy that taking it leaves capacity that can only be filled with low-value items, whereas skipping it allows two medium-ratio items that together yield more value. The greedy algorithm cannot “regret” the choice later — it has no lookahead.
In the earlier example, a greedy-by-ratio approach for 0/1 would take item 3 (ratio 1.5), then item 1 (ratio 1.33), resulting in total weight 5 and value 7. It cannot fit item 2 (weight 4, would exceed 7). The DP found the same optimum here, but a different example can break greedy:
Items: , , . Greedy takes item 1 (value 2, weight 1), leaving capacity for nothing else. Optimal: take item 2 (value 3). Greedy fails.
Comparison
| Property | 0/1 Knapsack | Fractional Knapsack |
|---|---|---|
| Can split items? | No | Yes |
| Solution method | DP | Greedy |
| Time | (pseudo-polynomial) | |
| Greedy works? | No | Yes |
| Optimal substructure | Yes | Yes |
| Greedy choice property | No | Yes |
Summary
| Property | Value |
|---|---|
| 0/1 knapsack | DP, pseudo-polynomial |
| Fractional knapsack | Greedy by value/weight ratio, |
| Why greedy fails for 0/1 | All-or-nothing constraint blocks lookahead |
| Why greedy works for fractional | Can always exchange lower-ratio for higher-ratio material |
| Space optimisation | 0/1 can be instead of |