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(i1,w)if wi>wmax(OPT(i1,w),  vi+OPT(i1,wwi))if wiw\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=573+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 logW\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: Θ(nlogn)\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)Θ(nlogn)\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, Θ(nlogn)\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)