Skip to content

state 16 of 32 · 5 min

The loop order that changes the answer

Rolled to one dimension, the knapsack loop looks like this:

code
for each item:
    for w from W down to weight[item]:
        best[w] = max(best[w], value[item] + best[w - weight[item]])

Change one word, down to up, and you have solved a different problem. Both versions are correct; they answer different questions.

Why

Going downwards, best[w - weight] still holds the value from the previous item, because you have not reached it yet this round. So each item is used at most once. That is 0/1 knapsack.

Going upwards, best[w - weight] has already been updated this round, possibly with this same item. So the item can be used again. That is unbounded knapsack, where you have unlimited copies.

code
items: one 3kg item worth 5.  capacity 9.

downwards  ->  5   (used once)
upwards    ->  15  (used three times)

Why this page exists

This is the single most common source of wrong answers in dynamic programming, and it never produces an error. The program runs, prints a number, and passes the small examples. On [3kg, 5] with capacity 3, both directions give 5.

The difference only appears when an item could usefully be repeated, which is rarely the first test case anybody tries.

The habit

Before writing the inner loop, say which problem you are solving:

  • Each item once means iterate capacity downwards.
  • Unlimited copies means upwards.

And test with a capacity that is a multiple of an item weight, since that is the input where the two disagree.