Skip to content
Part IA Lent Term

Knapsack Variants

Overview

The knapsack problem models resource allocation with a capacity constraint. Given nn items, each with weight wiw_i and value viv_i, and a knapsack with capacity WW, 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 OPT(i,w)\text{OPT}(i, w) be the maximum value achievable using items 11 through ii with capacity ww:

OPT(i,w)={0if i=0 or w=0OPT(i−1,w)if wi>wmax⁡(OPT(i−1,w),  vi+OPT(i−1,w−wi))if wi≤w\text{OPT}(i, w) = \begin{cases} 0 & \text{if } i = 0 \text{ or } w = 0 \\[4pt] \text{OPT}(i-1, w) & \text{if } w_i > w \\[4pt] \max\big(\text{OPT}(i-1, w),\; v_i + \text{OPT}(i-1, w - w_i)\big) & \text{if } w_i \le w \end{cases}

The two choices at each step: exclude item ii (value unchanged, capacity unchanged), or include item ii (gain viv_i, consume wiw_i of capacity).

Example

W=7W = 7, items: (w1=3,v1=4)(w_1=3, v_1=4), (w2=4,v2=5)(w_2=4, v_2=5), (w3=2,v3=3)(w_3=2, v_3=3).

DP table (rows = items considered, columns = capacity):

0/1 knapsack dynamic programming table: rows for items, columns for capacity

w=0w=01234567
i=0i=000000000
i=1i=100044444
i=2i=200045559
i=3i=300345789

Optimal: take items 1 and 3, total weight 3+2=5≤73+2=5 \le 7, total value 4+3=74+3=7.

Complexity

Time: Θ(nW)\Theta(nW). Space: Θ(nW)\Theta(nW) or Θ(W)\Theta(W) with space optimisation (only previous row needed). This is pseudo-polynomial: polynomial in the numeric value WW, but not in the input size log⁡W\log W. If WW is large, the algorithm is impractical.

Fractional Knapsack (Greedy)

Items can be split arbitrarily. The greedy strategy:

  1. Compute value per unit weight: vi/wiv_i / w_i for each item.
  2. Sort items by this ratio (descending).
  3. 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: Θ(nlog⁡n)\Theta(n \log n) for sorting, Θ(n)\Theta(n) for selection.

Example (Same Items)

(w1=3,v1=4,v/w=1.33)(w_1=3, v_1=4, v/w = 1.33), (w2=4,v2=5,v/w=1.25)(w_2=4, v_2=5, v/w = 1.25), (w3=2,v3=3,v/w=1.5)(w_3=2, v_3=3, v/w = 1.5). Capacity W=7W = 7.

  1. Item 3: ratio 1.5, take all → value 3, capacity left 5.
  2. Item 1: ratio 1.33, take all → value 4, capacity left 2.
  3. Item 2: ratio 1.25, take 2/4=0.52/4 = 0.5 → value 2.5.

Total: 3+4+2.5=9.53 + 4 + 2.5 = 9.5. (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: (1,2,ratio 2.0)(1, 2, \text{ratio } 2.0), (2,3,ratio 1.5)(2, 3, \text{ratio } 1.5), W=2W = 2. Greedy takes item 1 (value 2, weight 1), leaving capacity for nothing else. Optimal: take item 2 (value 3). Greedy fails.

Comparison

Property0/1 KnapsackFractional Knapsack
Can split items?NoYes
Solution methodDPGreedy
TimeΘ(nW)\Theta(nW) (pseudo-polynomial)Θ(nlog⁡n)\Theta(n \log n)
Greedy works?NoYes
Optimal substructureYesYes
Greedy choice propertyNoYes

Summary

PropertyValue
0/1 knapsackDP, Θ(nW)\Theta(nW) pseudo-polynomial
Fractional knapsackGreedy by value/weight ratio, Θ(nlog⁡n)\Theta(n \log n)
Why greedy fails for 0/1All-or-nothing constraint blocks lookahead
Why greedy works for fractionalCan always exchange lower-ratio for higher-ratio material
Space optimisation0/1 can be Θ(W)\Theta(W) instead of Θ(nW)\Theta(nW)