0/1 Knapsack
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.| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|---|
| 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.
Complexity
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
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.
Row zero is all zeros: with no items, every capacity is worth nothing. Every later answer stands on this base.
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).
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.
Write the bigger of the two. That is the whole algorithm: every cell reads at most two earlier cells.
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).
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.
| Step | Item | What happened |
|---|---|---|
| 1 | 1 | Capacity 2: take it - 3 + 0 (best of the 0 kg left) = 3 beats leaving it at 0. |
| 2 | 1 | Capacity 3: take it - 3 + 0 (best of the 1 kg left) = 3 beats leaving it at 0. |
| 3 | 1 | Capacity 4: take it - 3 + 0 (best of the 2 kg left) = 3 beats leaving it at 0. |
| 4 | 1 | Capacity 5: take it - 3 + 0 (best of the 3 kg left) = 3 beats leaving it at 0. |
| 5 | 1 | Capacity 6: take it - 3 + 0 (best of the 4 kg left) = 3 beats leaving it at 0. |
| 6 | 1 | Capacity 7: take it - 3 + 0 (best of the 5 kg left) = 3 beats leaving it at 0. |
| 7 | 1 | Capacity 8: take it - 3 + 0 (best of the 6 kg left) = 3 beats leaving it at 0. |
| 8 | 2 | Capacity 3: take it - 4 + 0 (best of the 0 kg left) = 4 beats leaving it at 3. |
| 9 | 2 | Capacity 4: take it - 4 + 0 (best of the 1 kg left) = 4 beats leaving it at 3. |
| 10 | 2 | Capacity 5: take it - 4 + 3 (best of the 2 kg left) = 7 beats leaving it at 3. |
| 11 | 2 | Capacity 6: take it - 4 + 3 (best of the 3 kg left) = 7 beats leaving it at 3. |
| 12 | 2 | Capacity 7: take it - 4 + 3 (best of the 4 kg left) = 7 beats leaving it at 3. |
| 13 | 2 | Capacity 8: take it - 4 + 3 (best of the 5 kg left) = 7 beats leaving it at 3. |
| 14 | 3 | Capacity 4: take it - 5 + 0 (best of the 0 kg left) = 5 beats leaving it at 4. |
| 15 | 3 | Capacity 5: skip it - taking would give only 5, the 7 from above is better. |
| 16 | 3 | Capacity 6: take it - 5 + 3 (best of the 2 kg left) = 8 beats leaving it at 7. |
| 17 | 3 | Capacity 7: take it - 5 + 4 (best of the 3 kg left) = 9 beats leaving it at 7. |
| 18 | 3 | Capacity 8: take it - 5 + 4 (best of the 4 kg left) = 9 beats leaving it at 7. |
| 19 | 4 | Capacity 5: skip it - taking would give only 6, the 7 from above is better. |
| 20 | 4 | Capacity 6: skip it - taking would give only 6, the 8 from above is better. |
| 21 | 4 | Capacity 7: a tie - taking it also gives 9. Keep the 9 and skip it. |
| 22 | 4 | Capacity 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
| Algorithm | Best | Average | Worst | Space | Stable |
|---|---|---|---|---|---|
| 0/1 Knapsackthis page | O(n·W) | O(n·W) | O(n·W) | O(W) | - |
| Coin Change | O(n·a) | O(n·a) | O(n·a) | O(a) | - |
| Longest Common Subsequence | O(n·m) | O(n·m) | O(n·m) | O(n·m) | - |
| Fibonacci: Memo vs Tabulation | O(n) | O(n) | O(n) | O(n) | - |