0/1 Knapsack

Dynamic Programming
avg O(n·W)

The 0/1 knapsack is THE resource-allocation problem: a fixed budget of space, money, or time, and a list of things that each cost some of it and pay back some value. Take an item whole, or leave it - no halves, hence "0/1". Trying every subset costs O(2^n); the knapsack table gets the exact best answer in O(n·W) by asking one tiny question per cell: take it, or skip it? Learn this table once and you will recognize it everywhere, from cargo loading to sprint planning.

Watch the bag get packed

Press play - or drag the timeline and step through it yourself.
Item 1Cells filled 0Decisions 0Step 1 / 48
012345678
no items·········
+ (w2, v3)·········
+ (w3, v4)·········
+ (w4, v5)·········
+ (w5, v6)·········

The bag holds 8 kg. Four items: (2 kg, value 3), (3 kg, value 4), (4 kg, value 5), (5 kg, value 6). Each cell will hold the best value using the items so far, at that capacity.

deciding this cell the two options items in the bag

Complexity

Best
O(n·W)
Input already in order
Average
O(n·W)
Normal mixed input
Worst
O(n·W)
Worst possible input
Space
O(W)
Extra memory used

Packing one backpack for a trip

Your class trip allows one backpack, 8 kg max. On your bed: a camera, a game console, books, snacks - each has a weight, and each has a 'how much do I want this' score. You cannot bring half a console. So for each item you ask: if I take it, is its score worth the space it steals from everything else? Grabbing the single best-looking item first can trap you - it may block two smaller things that together score more. The knapsack table checks every trade-off honestly and tells you the best bag you could possibly pack.

How it works, step by step

  1. Build a table: one row per item, one column per capacity from 0 to W. Cell [i][c] means: the best value using only the first i items, with c capacity.

  2. Row zero is all zeros: with no items, every capacity is worth nothing. Every later answer stands on this base.

  3. Fill row by row. Each cell is one decision about item i. Option one, skip it: the value is the cell right above (same capacity, one item fewer).

  4. Option two, take it (only if it fits, c >= weight): its value plus the cell above-left at [i-1][c - weight] - the best you could do with the space that remains.

  5. Write the bigger of the two. That is the whole algorithm: every cell reads at most two earlier cells.

  6. The bottom-right cell is the best possible value. To learn which items: walk back up. If a cell differs from the one above, that item was taken - subtract its weight and keep climbing.

The code, in JavaScript

The version the animation shows. dp[i][c] = best value using the first i items with capacity c. Two reads per cell: skip (above) or take (above-left plus my value).

javascript
function knapsack(items, capacity) {
  const n = items.length;
  // (n+1) x (capacity+1), row 0 = "no items" = all zeros
  const dp = Array.from({ length: n + 1 }, () =>
    new Array(capacity + 1).fill(0)
  );

  for (let i = 1; i <= n; i++) {
    const { w, v } = items[i - 1];
    for (let c = 0; c <= capacity; c++) {
      dp[i][c] = dp[i - 1][c];               // option 1: skip the item
      if (c >= w) {
        // option 2: take it - its value + best of the space left
        dp[i][c] = Math.max(dp[i][c], dp[i - 1][c - w] + v);
      }
    }
  }

  return dp[n][capacity];
}

const items = [
  { w: 2, v: 3 },
  { w: 3, v: 4 },
  { w: 4, v: 5 },
  { w: 5, v: 6 },
];
knapsack(items, 8);   // → 10  (items 2 and 4: weight 3+5, value 4+6)

Dry run: packing a bag of capacity 8 from 4 items

The same steps the visualizer plays, written as a table. Generated by running the real algorithm - not written by hand.

StepItemWhat happened
11Capacity 2: take it - 3 + 0 (best of the 0 kg left) = 3 beats leaving it at 0.
21Capacity 3: take it - 3 + 0 (best of the 1 kg left) = 3 beats leaving it at 0.
31Capacity 4: take it - 3 + 0 (best of the 2 kg left) = 3 beats leaving it at 0.
41Capacity 5: take it - 3 + 0 (best of the 3 kg left) = 3 beats leaving it at 0.
51Capacity 6: take it - 3 + 0 (best of the 4 kg left) = 3 beats leaving it at 0.
61Capacity 7: take it - 3 + 0 (best of the 5 kg left) = 3 beats leaving it at 0.
71Capacity 8: take it - 3 + 0 (best of the 6 kg left) = 3 beats leaving it at 0.
82Capacity 3: take it - 4 + 0 (best of the 0 kg left) = 4 beats leaving it at 3.
92Capacity 4: take it - 4 + 0 (best of the 1 kg left) = 4 beats leaving it at 3.
102Capacity 5: take it - 4 + 3 (best of the 2 kg left) = 7 beats leaving it at 3.
112Capacity 6: take it - 4 + 3 (best of the 3 kg left) = 7 beats leaving it at 3.
122Capacity 7: take it - 4 + 3 (best of the 4 kg left) = 7 beats leaving it at 3.
132Capacity 8: take it - 4 + 3 (best of the 5 kg left) = 7 beats leaving it at 3.
143Capacity 4: take it - 5 + 0 (best of the 0 kg left) = 5 beats leaving it at 4.
153Capacity 5: skip it - taking would give only 5, the 7 from above is better.
163Capacity 6: take it - 5 + 3 (best of the 2 kg left) = 8 beats leaving it at 7.
173Capacity 7: take it - 5 + 4 (best of the 3 kg left) = 9 beats leaving it at 7.
183Capacity 8: take it - 5 + 4 (best of the 4 kg left) = 9 beats leaving it at 7.
194Capacity 5: skip it - taking would give only 6, the 7 from above is better.
204Capacity 6: skip it - taking would give only 6, the 8 from above is better.
214Capacity 7: a tie - taking it also gives 9. Keep the 9 and skip it.
224Capacity 8: take it - 6 + 4 (best of the 3 kg left) = 10 beats leaving it at 9.

Good choice when…

  • A fixed budget and indivisible choices, each with a cost and a value: cargo on a truck, features in a sprint, servers under a power cap, projects under a budget.
  • You need the exact optimum, not a good guess - and n times W is small enough to afford (say, under a few tens of millions of cells).
  • Subset-sum questions: 'can some subset hit exactly S?' or 'split into two equal halves?' - the same table with true/false cells.
  • As the template for a whole family of DP problems: anything shaped like 'for each thing, take it or leave it, under a limit'.

Bad choice when…

  • Items can be split - sand, fuel, money streams. That is fractional knapsack: sort by value per kg and pour greedily, O(n log n), no table needed.
  • The capacity is a huge number (millions, billions). O(n·W) explodes even for a handful of items - look at meet-in-the-middle or branch and bound instead.
  • Each item can be taken many times - that is unbounded knapsack (the coin-change family). Related, but the loop direction and reasoning change.

Common mistakes

  • In the 1-D version the capacity loop must run backwards. Forwards, dp[c - w] already contains the current item, so it gets packed again and again - you silently solve unbounded knapsack. With our scene, forwards returns 12 (the 2 kg item four times) instead of 10.
  • O(n·W) looks polynomial but is pseudo-polynomial: W is a number in the input, not a size. Capacity 8 means 9 columns; capacity 2 billion means 2 billion columns from the same few input digits. This is why knapsack stays NP-hard despite the 'fast' table.
  • Greedy by value-per-weight fails for 0/1. Capacity 4, items (w3, v5) and two of (w2, v3): the ratio picks (w3, v5) first, blocking both others - total 5. Best is the two small ones - total 6. If a greedy answer were enough, you would not need the table.
  • Do not mix the problems up in an interview: fractional knapsack IS greedy (ratio sort is provably optimal there), 0/1 is not. Saying 'knapsack, so greedy by ratio' is exactly backwards for the 0/1 version.

0/1 Knapsack vs. its closest relatives

AlgorithmBestAverageWorstSpaceStable
0/1 Knapsackthis pageO(n·W)O(n·W)O(n·W)O(W)-
Coin ChangeO(n·a)O(n·a)O(n·a)O(a)-
Longest Common SubsequenceO(n·m)O(n·m)O(n·m)O(n·m)-
Fibonacci: Memo vs TabulationO(n)O(n)O(n)O(n)-