This deck covers 0/1 knapsack, coin change in both its minimum-coin and combination-counting forms, and rod cutting, making the setup explicit every time: define the state in words, write the take-or-skip or best-choice recurrence, pin down the base case, fill the table in dependency order, and reconstruct the items, coins, or cuts actually chosen. It targets four real misconceptions: using a best-ratio greedy strategy on 0/1 knapsack, accidentally reusing a single-copy item, using a greedy coin heuristic on a coin system where it overshoots the true minimum, and an off-by-one in the table's capacity or amount dimension. Every recurrence, table trace, and reconstruction was verified by hand and cross-checked against brute-force enumeration.
Subject: CS3000 Algorithms · 133 slides · symbolic lesson
Open the interactive version of this deck · Homework for this lesson
Objectives
This lesson covers three classic dynamic programming problems that all share one skeleton: define a state, write a take-or-skip (or best-choice) recurrence, set a base case, and fill a table in the right order. By the end you can:
Warm-up
Discussion prompt
Before we open Dynamic Programming II: Knapsack, Coin Change & Rod Cutting: without looking back, what was the main idea of Dynamic Programming I: Memoization, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
That deck gives the two ingredients that make dynamic programming apply, then shows the naive exponential recursion for Fibonacci and why it recomputes the same values. It presents the two fixes - top-down memoization and bottom-up tabulation - through a repeatable method for defining the state, writing the recurrence, and choosing the base cases, with Fibonacci and climbing stairs fully hand-traced. It targets four real misconceptions: reaching for dynamic programming when the subproblems never actually overlap, a wrong or missing base case that corrupts an entire table, a memo that is written but never checked before recursing, and a state defined too ambiguously to support a clean recurrence.
Concept
Before any new material: cover the screen.
You have named 13 reusable moves so far. Say as many as you can out loud, by number, from memory.
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Here they are. Score yourself.
Today adds no new moves. Every proof in this lesson is built out of the list above. That is the whole point of the list.
The question that starts every proof from here on is not how do I begin. It is which of these applies here?
Counterexample
Discussion prompt
You have named 13 reusable moves so far. Say as many as you can out loud, by number, from memory.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Concept
Every problem in this lesson is solvable by dynamic programming for the same two reasons. First, optimal substructure: the best answer to the whole problem is built out of the best answers to smaller versions of the same problem.
overlapping subproblems — The same smaller subproblem gets asked again and again inside a naive recursive solution. Caching each subproblem's answer once, instead of recomputing it, is exactly what turns exponential recursion into a fast table fill.
Whenever you meet a new problem, check for these two ingredients first. If both are present, a DP table is almost always the right tool.
Analogy
Discussion prompt
Explain Two ingredients every DP needs by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Whenever you meet a new problem, check for these two ingredients first. If both are present, a DP table is almost always the right tool.
Concept
You are packing a bag. You have a list of items, each with its own weight and value, and a bag that holds only so much total weight. You may take each item completely or leave it entirely - no cutting an item in half.
The goal: choose the subset of items whose total weight is at or under the bag's capacity, with the largest possible total value.
| item | weight | value |
|---|---|---|
| A | 2 | 3 |
| B | 3 | 4 |
| C | 4 | 5 |
| D | 5 | 6 |
We will trace this exact set of four items through the whole lesson, with a bag capacity of 5.
Pattern
Step through it
Step through The 0/1 knapsack problem one row at a time. What is driving the change, and what would the row after the last one be?
Picture it
Animation
Shows: The knapsack decision — a rendered Manim animation.
Rendered with Manim.
Takeaway: Both options refer only to the row above, which is why one pass suffices.
Concept
The name 0/1 describes the only two choices available for every item: take zero copies of it, or take exactly one copy. There is no 'take it twice' and no 'take a fraction of it.'
0/1 knapsack — A knapsack variant where each item exists in a single copy and must be taken whole or skipped entirely. Later in this lesson you will meet the opposite kind of decision - unlimited supply - in coin change and rod cutting.
Definition probe
Sort into buckets
Every line below is part of the definition of overlapping subproblems or of 0/1 knapsack — one or the other, never both. Put each where it belongs.
Intuition
Imagine deciding whether to take item C. The right choice depends entirely on how much room is left in the bag at that exact moment - item C might be worth taking with 4 units of room free and not worth it with only 1 unit free.
Because the decision changes with the remaining room, remaining room has to be part of what we remember. That is why the state tracks a capacity value, not just which items have been considered.
Explain it
Discussion prompt
Explain Why the capacity must join the state to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Because the decision changes with the remaining room, remaining room has to be part of what we remember. That is why the state tracks a capacity value, not just which items have been considered.
Concept
Let the state be: consider only the first so-many items, with a bag of so-much capacity. Store the best total value achievable under exactly those two limits.
\[ dp[i][w] = \text{best value using only the first } i \text{ items, capacity } w \]
The first number can range from zero items considered up to all of them. The second can range from zero capacity up to the bag's full capacity. The final answer is the entry for every item, at the full capacity.
Concept
Every proof of this kind has the same five or six moves in the same order. The order is not something you rediscover each time.
It is on the right. It will stay on the right through the worked examples that follow.
Why this matters: the structure is now handled. You are not spending working memory on what comes next — you are spending all of it on the one hard step.
Step 1 is where every failed DP fails. A subproblem you cannot say in one sentence is a subproblem you cannot write a recurrence for, and steps 2 through 6 will not rescue it.
Picture it
Animation
Shows: When greedy coin change IS correct — a rendered Manim animation.
Rendered with Manim.
Takeaway: Greedy working on your currency is not evidence it works in general.
Intuition
What move should we make next?
The subproblem sentence for 0/1 knapsack:
\[ dp[i][w] = \text{the best value using only the first } i \text{ items, with capacity } w \]
Two dimensions, because capacity is a thing you can run out of.
Same move as the stairs and as Kadane. Name it, then say how many cases it produces here.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Fill the middle
Fill in the blanks
From The take-or-skip recurrence — finish the line. Write what belongs on the right of the equals sign before you look.
\textdp[i-1][w] dp[i][w] = ___
Why: Producing the right-hand side unprompted is the difference between recognising this line and being able to use it. The best value stays whatever it was using one fewer item, at the same capacity - the new item contributes nothing.
Concept
To fill in one entry, look at the newest item under consideration and ask exactly one question: is it better to skip this item, or to take it?
Skip the item
Why: The best value stays whatever it was using one fewer item, at the same capacity - the new item contributes nothing.
\[ \text{skip: } dp[i][w] = dp[i-1][w] \]
Take the item, only if it fits
Why: Add the item's value to the best value achievable with one fewer item and the capacity reduced by this item's weight.
\[ \text{take: } dp[i][w] = dp[i-1][w-\text{weight}_i] + \text{value}_i \]
Whichever option gives the larger value wins.
\[ dp[i][w] = \max\big(dp[i-1][w],\ dp[i-1][w-\text{weight}_i] + \text{value}_i\big) \]
Notation
Annotate
From The take-or-skip recurrence — read this one piece at a time. What is each part doing?
On: \( \text{skip: } dp[i][w] = dp[i-1][w] \)
Concept
The move: #13 (Name the subproblem), then #12 (Case-split on the last decision).
The last decision is about item i, and it has exactly two answers
Why: Either item i is in the chosen set or it is not. Nothing else is possible, so the split is complete by construction.
\[ dp[i][w] = \max\big(\, \underbrace{dp[i-1][w]}_{\text{skip it}}, \;\; \underbrace{v_{i} + dp[i-1][w - w_{i}]}_{\text{take it}} \,\big) \]
Why the take branch goes to i-1 and not to i
Why: Because this is 0/1: once item i is taken it is gone. Sending the take branch back to i would allow reusing it, which is the unbounded problem, not this one.
Both branches drop to i-1. That single detail is the entire difference between 0/1 knapsack and the unbounded version — and it is visible in the recurrence, not in the code.
Concept
Sometimes the current item's weight is larger than the remaining capacity in that cell. Then there is no 'take' option to compare against - taking it would require negative remaining room, which is impossible.
\[ \text{if weight}_i > w: \quad dp[i][w] = dp[i-1][w] \]
In that case skipping is not a choice you weigh against taking - it is the only legal option, so the entry simply copies the row above it.
Concept
Two edges of the table are known before any recurrence runs. With zero items to choose from, no value can be collected, no matter the capacity.
\[ dp[0][w] = 0 \quad \text{for every } w \]
And with zero capacity, nothing fits, no matter how many items are available.
\[ dp[i][0] = 0 \quad \text{for every } i \]
Picture it
Animation
Shows: Why knapsack is not actually polynomial — a rendered Manim animation.
Rendered with Manim.
Takeaway: Doubling the digits of W doubles the table's width many times over.
Concept
Each row only needs values from the row directly above it, so the table fills one full row at a time, in order from the first item to the last.
Within a row, capacities can be filled in any order at all, because a 0/1 knapsack cell only ever depends on the row above it - never on another cell in its own row. Later in this lesson you will meet problems where that is not true.
Concept
Two nested loops fill a table, and the body is a single take-or-skip comparison. The loops are only there to make sure the two cells the comparison needs are already filled.
KNAPSACK(w, v, n, W)
for cap = 0 to W
dp[0][cap] = 0
for i = 1 to n
for cap = 0 to W
dp[i][cap] = dp[i-1][cap]
if w[i] <= cap
take = v[i] + dp[i-1][cap - w[i]]
dp[i][cap] = max(dp[i][cap], take)
return dp[n][W]Both cells that line 8 and line 6 read come from row i minus one, the row above. That is why the outer loop goes forward over items: the row you need is always the one you just finished.
Notation
Every line of KNAPSACK says one thing. Read the line, then read what it does — not the other way round.
Annotate
Invariant
Every cell asks the same question: the best value using only the first i items, with exactly this much capacity. Say that sentence at each cell before you look at its number.
Step through it
For each cell, name the two cells above it that its value came from.
Picture it
Animation
Shows: KNAPSACK executing: the current line of pseudocode is highlighted while the data it touches changes.
Rendered with Manim.
Takeaway: Take or skip, and both options read only from the row above — which is why filling row by row always works.
Concept
The table has one row per item and one column per capacity value, and each cell takes a fixed amount of work to fill.
\[ \text{time} = \Theta(n \cdot W) \]
where the number of items is n and the bag's capacity is W. This is not fast in the size of the input numbers themselves, since W can be large - this running time is called pseudo-polynomial.
\[ \text{space} = \Theta(n \cdot W) \]
for the full table, though it can be trimmed to a single row of size W if the chosen items don't need to be reconstructed afterward.
Picture it
Animation
Shows: Pricing the knapsack table — a rendered Manim animation.
Rendered with Manim.
Takeaway: States times work per state — the same formula as always.
Ranking
Put in order
Put the moves of Filling the knapsack table into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. The base case - every entry is 0 regardless of capacity.
Worked example
Four items, bag capacity 5. Fill dp[i][w] for i from 0 through 4 and w from 0 through 5.
| item | weight | value |
|---|---|---|
| A | 2 | 3 |
| B | 3 | 4 |
| C | 4 | 5 |
| D | 5 | 6 |
Row 0: zero items considered
Why: The base case - every entry is 0 regardless of capacity.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[0][w] | 0 | 0 | 0 | 0 | 0 | 0 |
Row 1: consider item A, weight 2 value 3
Why: Below capacity 2, A doesn't fit, so the entry copies row 0. From capacity 2 onward, taking A beats skipping it: 3 is bigger than 0.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[1][w] | 0 | 0 | 3 | 3 | 3 | 3 |
Row 2: consider item B, weight 3 value 4
Why: At capacity 3 and 4, taking B alone (value 4) beats the row above (3). At capacity 5, taking both A and B fits exactly: dp[1][2] plus 4 equals 3 plus 4, or 7, which beats the row above's 3.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[2][w] | 0 | 0 | 3 | 4 | 4 | 7 |
Row 3: consider item C, weight 4 value 5
Why: At capacity 4, taking C alone (value 5) beats the row above's 4. At capacity 5, taking C plus whatever fits in the remaining unit gives only 5, which loses to the row above's 7 - so C is skipped there.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[3][w] | 0 | 0 | 3 | 4 | 5 | 7 |
Row 4: consider item D, weight 5 value 6
Why: At capacity 5, taking D alone gives 6, which loses to the row above's 7. D is skipped, and the row is identical to row 3.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[4][w] | 0 | 0 | 3 | 4 | 5 | 7 |
Verify the final entry against a direct count
Why: The subset containing A and B weighs 2 plus 3, exactly 5, and is worth 3 plus 4, or 7 - matching the final table entry. No other subset within the capacity beats it: D alone is only 6, and adding C or D to A or B always exceeds weight 5.
\[ dp[4][5] = 7 \]
Picture it
Animation
Shows: The knapsack table, filling in — a rendered Manim animation.
Rendered with Manim.
Takeaway: Every cell asks one question: take this item, or skip it?
Concept
The table tells you the best value, but not which items produced it. For that, walk backward through the table you already filled, one row at a time.
Compare the current cell to the cell directly above it
Why: If the two values are equal, the current item added nothing - it was skipped, so move straight up to the row above at the same capacity.
If the values differ, the item was taken
Why: Record it, then jump to the row above at a reduced capacity: subtract that item's weight before moving up.
\[ \text{if } dp[i][w] \neq dp[i-1][w]: \text{ item } i \text{ taken; go to } dp[i-1][w-\text{weight}_i] \]
Repeat until row 0 or capacity 0 is reached. Every item recorded along the way is part of an optimal choice.
Step zero
Discussion prompt
Reconstructing the chosen items — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Compare dp[4][5] to dp[3][5]
Answer:
Worked example
Start at the final answer cell and walk backward using the filled table from before.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[0][w] | 0 | 0 | 0 | 0 | 0 | 0 |
| dp[1][w] | 0 | 0 | 3 | 3 | 3 | 3 |
| dp[2][w] | 0 | 0 | 3 | 4 | 4 | 7 |
| dp[3][w] | 0 | 0 | 3 | 4 | 5 | 7 |
| dp[4][w] | 0 | 0 | 3 | 4 | 5 | 7 |
Compare dp[4][5] to dp[3][5]
Why: Both are 7 - equal - so item D was skipped. Move up to dp[3][5].
Compare dp[3][5] to dp[2][5]
Why: Both are 7 - equal - so item C was skipped too. Move up to dp[2][5].
Compare dp[2][5] to dp[1][5]
Why: 7 versus 3 - different. Item B was taken. Record B, and move to dp[1][2], since capacity 5 minus B's weight 3 is 2.
Compare dp[1][2] to dp[0][2]
Why: 3 versus 0 - different. Item A was taken. Record A, and move to dp[0][0], since capacity 2 minus A's weight 2 is 0.
Verify the reconstructed set
Why: Items A and B have total weight 2 plus 3, which is 5 and fits exactly, and total value 3 plus 4, which is 7 - matching the table entry. The walk-back recovered exactly the subset found by direct count earlier.
\[ \{A, B\}: \text{ weight } 5,\ \text{value } 7 \]
Picture it
Animation
Shows: Each line of the worked example "Reconstructing the chosen items", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Items A and B have total weight 2 plus 3, which is 5 and fits exactly, and total value 3 plus 4, which is 7 - matching the table entry. The walk-back recovered exactly the subset found by direct count earlier.
Intuition
A natural instinct: rank every item by value per unit of weight, then grab items in that order until the bag is full. That instinct is exactly correct for a different problem - one where items can be split into fractions.
For 0/1 knapsack, that instinct can lock in an early item that blocks a much better later combination, because a whole item, once taken, can never be partially given back.
Intuition
What feels wrong about this?
Capacity 10. Two items:
\[ \text{item A: weight } 6, \; \text{value } 30 \quad (\text{ratio } 5) \]
\[ \text{item B: weight } 5, \; \text{value } 20 \quad (\text{ratio } 4) \]
Best ratio first takes A, leaving capacity 4, which fits nothing else. Total: 30.
_Plain English only. No notation, no algebra. Just say what bothers you._
The feeling: there are four units of capacity sitting there doing nothing, and the rule that got you here never considered that.
That feeling is the proof. It is not a substitute for the proof — it is the thing the proof writes down.
Two of item B would weigh 10 and be worth 40. Greedy optimizes the next choice; it cannot see the hole it leaves behind. That hole is exactly what the take-or-skip case split does see, because the skip branch is a real option.
Anomaly
Predict first
A student writes this, and it looks reasonable:
Capacity 50. Three items, ranked by value per unit of weight.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Item 1 (ratio 6) fits in 50, leaving 40.
Check every combination that fits in capacity 50 instead of trusting the ratio order.
Why: Item 1 (ratio 6) fits in 50, leaving 40. Item 2 (ratio 5) fits in the remaining 40, leaving 20. Item 3 needs 30 but only 20 remains, so it is skipped entirely - 0/1 allows no partial items.
Trap
Capacity 50. Three items, ranked by value per unit of weight.
| item | weight | value | value per weight |
|---|---|---|---|
| 1 | 10 | 60 | 6 |
| 2 | 20 | 100 | 5 |
| 3 | 30 | 120 | 4 |
Take items in order of best ratio: item 1, then item 2
Why: Item 1 (ratio 6) fits in 50, leaving 40. Item 2 (ratio 5) fits in the remaining 40, leaving 20. Item 3 needs 30 but only 20 remains, so it is skipped entirely - 0/1 allows no partial items.
\[ \text{greedy total} = 60 + 100 = 160,\ \text{weight used} = 30 \]
Check every combination that fits in capacity 50 instead of trusting the ratio order.
| subset | weight | value |
|---|---|---|
| items 1,2 | 30 | 160 |
| items 1,3 | 40 | 180 |
| items 2,3 | 50 | 220 |
Take items 2 and 3, skipping item 1 entirely
Why: Weight 20 plus 30 is 50, fitting exactly, and value 100 plus 120 is 220 - beating every other combination, including the greedy pick of 160. The single highest-ratio item was best left out.
\[ \text{optimal} = 220 > 160 \]
Pattern
Step through it
Step through Trap: greedy best-ratio fails for 0/1 knapsack one row at a time. What is driving the change, and what would the row after the last one be?
Step zero
Discussion prompt
Greedy works for the fractional version — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Take item 1 whole
Answer:
Worked example
Same three items and capacity 50 - but now suppose a fraction of any item can be taken, earning that same fraction of its value. Fill the capacity using best ratio first, allowed this time to slice the last item.
| item | weight | value | value per weight |
|---|---|---|---|
| 1 | 10 | 60 | 6 |
| 2 | 20 | 100 | 5 |
| 3 | 30 | 120 | 4 |
Take item 1 whole
Why: Ratio 6, the best available, and it fully fits: 10 used, 40 remaining.
\[ \text{running value} = 60,\ \text{remaining capacity} = 40 \]
Take item 2 whole
Why: Ratio 5, next best, and it fully fits: 20 used, 20 remaining.
\[ \text{running value} = 160,\ \text{remaining capacity} = 20 \]
Take two-thirds of item 3
Why: Only 20 of item 3's 30 weight units still fit, so take that fraction, two thirds, of both its weight and its value.
\[ \tfrac{20}{30} \times 120 = 80 \]
Verify the fractional total uses the full capacity
Why: Total weight is 10 plus 20 plus 20, which is 50, exactly the capacity, and total value is 60 plus 100 plus 80, which is 240 - higher than either the 0/1 greedy result of 160 or the 0/1 optimum of 220, because slicing item 3 recovers value 0/1 could never reach.
\[ \text{fractional total} = 240 \]
Picture it
Animation
Shows: Why greedy fails on coin change — a rendered Manim animation.
Rendered with Manim.
Takeaway: Taking the biggest coin first is locally sensible and globally wrong.
Anomaly
Predict first
A student writes this, and it looks reasonable:
One item only: A, weight 2, value 3. Bag capacity 6. A student writes the recurrence so the 'take' branch looks at the same row instead of the row above.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Looking at the same row lets item A be counted again in a cell that already used it, so the table effectively allows A to be packed three times: weight 2 plus 2 plus 2 is 6, value 3 plus 3 plus 3 is 9.
Only one physical copy of item A exists. The take branch must look at the row above - one fewer item available - never at the current row.
Why: Looking at the same row lets item A be counted again in a cell that already used it, so the table effectively allows A to be packed three times: weight 2 plus 2 plus 2 is 6, value 3 plus 3 plus 3 is 9.
Trap
One item only: A, weight 2, value 3. Bag capacity 6. A student writes the recurrence so the 'take' branch looks at the same row instead of the row above.
\[ \text{wrong take branch: } dp[i][w] = dp[i][w-\text{weight}_i] + \text{value}_i \]
Fill using the same-row take branch
Why: Looking at the same row lets item A be counted again in a cell that already used it, so the table effectively allows A to be packed three times: weight 2 plus 2 plus 2 is 6, value 3 plus 3 plus 3 is 9.
\[ \text{wrong result: } dp[6] = 9\ (\text{three copies of A}) \]
Only one physical copy of item A exists. The take branch must look at the row above - one fewer item available - never at the current row.
\[ \text{correct take branch: } dp[i][w] = dp[i-1][w-\text{weight}_i] + \text{value}_i \]
Fill using the row-above take branch
Why: With only the row above available, item A can be used at most once. The single copy gives weight 2, value 3, leaving 4 units of capacity unused since nothing else is available to fill it.
\[ \text{correct result: } dp[6] = 3\ (\text{one copy of A}) \]
Anomaly
Predict first
A student writes this, and it looks reasonable:
Same four items, capacity 5. A student sizes the table with 5 columns - for capacities 0 through 4 - thinking 'capacity 5' means 5 columns.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: The column for the actual capacity, 5, was never allocated, so the student reads the entry at capacity 4, which is 5 - undercounting the true optimum by 2.
A capacity of 5 means capacities 0, 1, 2, 3, 4, and 5 are all possible column values - six columns, not five.
Why: The column for the actual capacity, 5, was never allocated, so the student reads the entry at capacity 4, which is 5 - undercounting the true optimum by 2.
Trap
Same four items, capacity 5. A student sizes the table with 5 columns - for capacities 0 through 4 - thinking 'capacity 5' means 5 columns.
| w | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[4][w] | 0 | 0 | 3 | 4 | 5 |
Read the last available column as the answer
Why: The column for the actual capacity, 5, was never allocated, so the student reads the entry at capacity 4, which is 5 - undercounting the true optimum by 2.
\[ \text{reported answer: } 5\ (\text{wrong}) \]
A capacity of 5 means capacities 0, 1, 2, 3, 4, and 5 are all possible column values - six columns, not five.
| w | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[4][w] | 0 | 0 | 3 | 4 | 5 | 7 |
Size the table with capacity plus one columns
Why: With the column for capacity 5 correctly included, the entry there reads 7 directly - the true optimum already found by direct count and by walking the table back.
\[ \text{correct answer: } 7 \]
Translation
\( \text{correct answer: } 7 \)
Draw it
Translate both ways. First write the expression above as a sentence with no symbols in it at all. Then cover it, and write your sentence back as notation. If the two versions disagree, the disagreement is the thing to fix.
Estimation
Predict first
Before trusting a DP table, it helps to see it confirmed against a full listing at least once. List every subset of the four items whose total weight is at most 5.
Commit before you compute: what does Double-checking with brute force come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify the table's best row against the DP answer
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. The largest value among all listed subsets is 7, from A and B together, and no other subset ties or beats it.
Worked example
Before trusting a DP table, it helps to see it confirmed against a full listing at least once. List every subset of the four items whose total weight is at most 5.
| subset | weight | value |
|---|---|---|
| none | 0 | 0 |
| A | 2 | 3 |
| B | 3 | 4 |
| C | 4 | 5 |
| D | 5 | 6 |
| A and B | 5 | 7 |
Rule out every remaining subset
Why: Any subset adding a second item to C or D exceeds weight 5 - for example A with C weighs 6, and A with D weighs 7 - so no other subset needs to be listed.
Verify the table's best row against the DP answer
Why: The largest value among all listed subsets is 7, from A and B together, and no other subset ties or beats it. This matches the filled table's final entry exactly.
\[ \max(0,3,4,5,6,7) = 7 = dp[4][5] \]
Pattern
Step through it
Step through Double-checking with brute force one row at a time. What is driving the change, and what would the row after the last one be?
Concept
You have coin denominations available in unlimited supply, and a target amount of money. Find the smallest number of coins that adds up to exactly that amount.
If no combination of coins reaches the amount exactly, that amount is simply unreachable - there is no valid combination to report.
Concept
In 0/1 knapsack, every item could be used at most once. Here, every coin denomination can be used as many times as needed - a coin worth 1 can appear five times in a row if that is the best combination.
unbounded choice — A decision that can be repeated any number of times, as opposed to a 0/1 decision that can be made at most once per item. Coin change and rod cutting are both unbounded; 0/1 knapsack is not.
Picture it
Animation
Shows: Unbounded coins look backwards, not upwards — a rendered Manim animation.
Rendered with Manim.
Takeaway: Reusing the current row is exactly what allows repeats.
Intuition
To make change for a large amount, you first need to know the best way to make every smaller amount - the minimum coins for a target is built directly out of the minimum coins for smaller amounts, whichever coin is tried last.
So the table is filled amount by amount, from 0 up to the target, and each entry only ever looks backward at smaller amounts already solved.
Picture it
Animation
Shows: Loop order decides what you count — a rendered Manim animation.
Rendered with Manim.
Takeaway: Two nearly identical programs answering different questions.
Intuition
Watch me not know the answer. This is what the first two minutes actually look like.
Minimum coins to make an amount, with an unlimited supply of each denomination.
Try the knapsack shape: an entry per coin index and per amount
Why: Knapsack just worked, and this looks like knapsack. Copy the state: dp[i][a] is the fewest coins using the first i denominations to make amount a.
It is correct but the second dimension is doing nothing
Why: Because coins are unlimited, no coin is ever used up. The take branch can go back to i, not i-1 — which means the coin index never actually constrains anything, and every row ends up identical to the row that considers all coins.
Dead end. Not a mistake — a move that was worth trying and did not pay off. This happens in most proofs.
Back up. Drop the dimension that carries no information
Why: The only thing the state needs to remember is the amount remaining. One dimension.
\[ dp[a] = 1 + \min_{c \,\in\, \text{coins},\; c \le a} dp[a - c] \]
The test for whether a dimension belongs in the state: remove it and ask whether the recurrence still has enough information. If it does, it never belonged.
The expert does not see the whole path in advance. The expert tries something, reads the result, and adjusts. That is the skill.
Concept
Let the state be a single number: the target amount of money. Store the fewest coins that add up to exactly that amount.
\[ dp[a] = \text{fewest coins that sum to exactly amount } a \]
Unlike knapsack, there is no item-index dimension here - every coin denomination is always available, so the state only needs to track the amount left to build.
Fill the middle
Fill in the blanks
From The recurrence for minimum coins — finish the line. Write what belongs on the right of the equals sign before you look.
dp[a] = \min_{c \le a} \big(1 + dp[a-c]\big)
Why: Producing the right-hand side unprompted is the difference between recognising this line and being able to use it. For each coin worth c that is no larger than the amount, using it last means the rest of the amount was already solved optimally.
Concept
Try every coin denomination as the last coin added
Why: For each coin worth c that is no larger than the amount, using it last means the rest of the amount was already solved optimally.
\[ dp[a] = 1 + dp[a-c] \quad \text{for each coin } c \le a \]
Take the best choice of last coin
Why: Different coins tried last give different totals; keep whichever one gives the fewest coins overall.
\[ dp[a] = \min_{c \le a} \big(1 + dp[a-c]\big) \]
Concept
Making an amount of zero needs no coins at all - that is the one fact known before the recurrence runs.
\[ dp[0] = 0 \]
Concept
If every coin denomination is larger than the amount, or every smaller amount it could reduce to is itself unreachable, then the amount cannot be made at all.
Represent that with a placeholder value larger than any real answer could be, often called infinity, so that comparing it against a real coin count always loses, and it never gets mistaken for a valid answer.
\[ dp[a] = \infty \quad (\text{no coin combination reaches } a) \]
Concept
The table has one entry per amount from 0 to the target, and filling each entry checks every coin denomination once.
\[ \text{time} = \Theta(\text{amount} \times \text{number of coin denominations}) \]
\[ \text{space} = \Theta(\text{amount}) \]
since the table is just one row this time, not a full grid like knapsack's.
Picture it
Animation
Shows: Coin change, cell by cell — a rendered Manim animation.
Rendered with Manim.
Takeaway: Each amount looks back at the amounts one coin smaller.
Estimation
Predict first
Coins available: 1, 3, and 4, in unlimited supply. Target amount: 6. Fill dp[a] for a from 0 through 6.
Commit before you compute: what does Filling the minimum-coins table come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify by naming an actual combination
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Two coins of value 3 sum to exactly 6, matching the amount-6 entry of 2.
Worked example
Coins available: 1, 3, and 4, in unlimited supply. Target amount: 6. Fill dp[a] for a from 0 through 6.
Base case and amount 1
Why: The amount 0 needs 0 coins by definition. For amount 1, only coin 1 fits, giving 1 plus the amount-0 entry, which is 1.
| a | 0 | 1 |
|---|---|---|
| dp[a] | 0 | 1 |
Amounts 2 and 3
Why: For amount 2, only coin 1 fits: 1 plus the amount-1 entry is 2. For amount 3, coin 1 gives 1 plus the amount-2 entry, or 3, but coin 3 gives 1 plus the amount-0 entry, or 1 - the better choice.
| a | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 |
Amount 4
Why: Coin 1 gives 1 plus the amount-3 entry, or 2. Coin 4 gives 1 plus the amount-0 entry, or 1. Coin 4 is best.
| a | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 | 1 |
Amount 5
Why: Coin 1 gives 1 plus the amount-4 entry, or 2. Coin 3 gives 1 plus the amount-2 entry, or 3. Coin 4 gives 1 plus the amount-1 entry, or 2. The best is 2.
| a | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 | 1 | 2 |
Amount 6
Why: Coin 1 gives 1 plus the amount-5 entry, or 3. Coin 3 gives 1 plus the amount-3 entry, or 2. Coin 4 gives 1 plus the amount-2 entry, or 3. Coin 3 is best.
| a | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 | 1 | 2 | 2 |
Verify by naming an actual combination
Why: Two coins of value 3 sum to exactly 6, matching the amount-6 entry of 2. No single coin reaches 6, so one coin is impossible, confirming 2 really is the minimum.
\[ 3 + 3 = 6,\ \text{count} = 2 = dp[6] \]
Picture it
Animation
Shows: Each line of the worked example "Filling the minimum-coins table", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Two coins of value 3 sum to exactly 6, matching the amount-6 entry of 2. No single coin reaches 6, so one coin is impossible, confirming 2 really is the minimum.
Concept
Walk backward from the target amount, at each step finding which coin was the last one added.
Find the coin that achieves the minimum at this amount
Why: Check every coin c no larger than the current amount; the one where 1 plus the reduced-amount entry equals the current entry was used last.
\[ \text{coin } c \text{ used if } dp[a] = 1 + dp[a-c] \]
Record that coin and move to the smaller amount
Why: Subtract the chosen coin's value from the amount and repeat the search there.
Stop once the amount reaches 0. Every coin recorded along the way is part of an optimal combination.
Ranking
Put in order
Put the moves of Reconstructing the coins for amount 6 into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Coin 1: 1 plus the amount-5 entry is 1 plus 2, or 3 - not a match.
Worked example
Use the filled table from before to walk back from amount 6.
| a | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| dp[a] | 0 | 1 | 2 | 1 | 1 | 2 | 2 |
At amount 6, test each coin
Why: Coin 1: 1 plus the amount-5 entry is 1 plus 2, or 3 - not a match. Coin 3: 1 plus the amount-3 entry is 1 plus 1, or 2 - a match. Coin 4: 1 plus the amount-2 entry is 1 plus 2, or 3 - not a match.
\[ \text{coin 3 used; move to amount } 6-3=3 \]
At amount 3, test each coin again
Why: Coin 1: 1 plus the amount-2 entry is 1 plus 2, or 3 - not a match, since the amount-3 entry is 1. Coin 3: 1 plus the amount-0 entry is 1 plus 0, or 1 - a match.
\[ \text{coin 3 used; move to amount } 3-3=0 \]
Verify the recovered coins
Why: The walk-back recorded coin 3 twice, for a total of 3 plus 3, which is 6, using 2 coins - matching the amount-6 entry and the combination already confirmed by direct count.
\[ \{3, 3\}: \text{sum } 6,\ \text{count } 2 \]
Picture it
Animation
Shows: Each line of the worked example "Reconstructing the coins for amount 6", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: The walk-back recorded coin 3 twice, for a total of 3 plus 3, which is 6, using 2 coins - matching the amount-6 entry and the combination already confirmed by direct count.
Anomaly
Predict first
A student writes this, and it looks reasonable:
Coins 1, 3, and 4. Target amount 6. A student always grabs the largest coin that still fits, the way familiar coin systems usually allow.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Take a 4, leaving 2. Take a 1, leaving 1.
Check the DP table filled earlier instead of assuming the biggest coin first is always safe.
Why: Take a 4, leaving 2. Take a 1, leaving 1. Take another 1, leaving 0. Three coins total: 4 plus 1 plus 1.
Trap
Coins 1, 3, and 4. Target amount 6. A student always grabs the largest coin that still fits, the way familiar coin systems usually allow.
\[ \text{coins available, largest first: } 4, 3, 1 \]
Greedily take the largest coin each time
Why: Take a 4, leaving 2. Take a 1, leaving 1. Take another 1, leaving 0. Three coins total: 4 plus 1 plus 1.
\[ \text{greedy result: } 3 \text{ coins } (4+1+1=6) \]
Check the DP table filled earlier instead of assuming the biggest coin first is always safe.
\[ dp[6] = 2 \]
Use two coins of value 3 instead
Why: 3 plus 3 is 6, using only 2 coins - beating the greedy result of 3. On this coin system, the 'grab the biggest coin' rule genuinely gives the wrong answer; it only works for coin systems specially designed to make it safe.
\[ \text{optimal: } 2 \text{ coins } (3+3=6) < 3 \]
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
Concept
Same coins, same target amount - but now the question changes completely. Instead of the fewest coins, count every distinct combination of coins that sums to the amount, where order does not matter.
Using a coin of value 1 then one of value 2 is the same combination as using a coin of value 2 then one of value 1 - they use the same collection of coins, just listed in a different order.
Intuition
If the state only tracked the amount, and coins were scanned through in any order at every amount, the same combination could be built in more than one order and get counted twice.
To count combinations instead of orderings, process the coin denominations one type at a time - fully deciding how many of the first coin type to use before ever considering the second type - so each combination is only ever built in one fixed order.
Concept
This state needs two numbers: how many coin types have been made available so far, and the amount being built.
\[ dp[i][a] = \text{ways to make amount } a \text{ using only the first } i \text{ coin types} \]
The coin-type dimension is what keeps every combination counted exactly once, no matter what order the coin types happen to be listed in.
Intuition
What move should we make next?
Same coins, different question. Compare the two states:
\[ \text{minimum coins: } \; dp[a] \qquad \text{counting ways: } \; dp[i][a] \]
The counting version needs the coin index back. The minimum version did not.
Why does counting need a dimension that minimizing did not? Answer before the recurrence appears.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Concept
Don't use this coin type at all
Why: Every way to make the amount without this coin type was already counted using one fewer coin type.
\[ \text{without coin } i: \ dp[i-1][a] \]
Use at least one of this coin type
Why: Use one copy of coin i now, and count the remaining ways to make what's left - still allowing this same coin type again, since supply is unlimited.
\[ \text{with coin } i: \ dp[i][a - \text{value}_i] \]
Add the two counts together, since 'without this coin type' and 'with at least one' never overlap.
\[ dp[i][a] = dp[i-1][a] + dp[i][a-\text{value}_i] \]
Picture it
Animation
Shows: The fractional version is greedy — a rendered Manim animation.
Rendered with Manim.
Takeaway: One word in the problem statement changes the whole technique.
Concept
Notice the 'use this coin type' branch points at the same row, not the row above. That is only safe because the coin-type loop is the outer loop and the amount loop is the inner one - every cell in a row is filled left to right before moving to the next row.
If the loops were swapped - amounts on the outside, coin types on the inside - that same-row dependency would break, and the count would silently include orderings as if they were separate combinations.
Concept
With zero coin types available, there is exactly one way to make the amount zero - use nothing - and zero ways to make any positive amount, since there is nothing to build it from.
\[ dp[0][0] = 1, \qquad dp[0][a] = 0 \ \text{for } a > 0 \]
Picture it
Animation
Shows: Getting the base cases right — a rendered Manim animation.
Rendered with Manim.
Takeaway: The whole first row and first column, filled before anything else.
Step zero
Discussion prompt
Filling the counting-ways table — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Row for zero coin types
Answer:
Worked example
Coin types available, in order: value 1, then value 2. Target amount: 4.
Row for zero coin types
Why: Base case: exactly one way to make 0, using nothing, and zero ways to make anything positive.
| a | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[0][a] | 1 | 0 | 0 | 0 | 0 |
Row for coin types {1}
Why: Every amount can only be built from 1's, so there is exactly one way to make each amount: all 1's.
| a | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[1][a] | 1 | 1 | 1 | 1 | 1 |
Row for coin types {1, 2}, amounts 0 through 2
Why: Amount 0 gives 1, copied from the row above. Amount 1 also copies the row above, since a coin of 2 can't fit into amount 1. Amount 2 combines the row-above value 1 with the same-row value at amount 0, giving 1 plus 1, or 2 - either four... two 1's, or one 2.
| a | 0 | 1 | 2 |
|---|---|---|---|
| dp[2][a] | 1 | 1 | 2 |
Amounts 3 and 4
Why: Amount 3 combines the row-above value 1 with the same-row value at amount 1, giving 1 plus 1, or 2. Amount 4 combines the row-above value 1 with the same-row value at amount 2, giving 1 plus 2, or 3.
| a | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[2][a] | 1 | 1 | 2 | 2 | 3 |
Check the arithmetic in the final cell
Why: The amount-4 entry combines the row-above value at amount 4, which is 1 (all four coins are 1's), with the same-row value at amount 2, which is 2 (the ways to make 2, each with an extra coin of value 2 added on top): 1 plus 2 is 3.
\[ dp[2][4] = 1 + 2 = 3 \]
Picture it
Animation
Shows: Counting ways, not minimising — a rendered Manim animation.
Rendered with Manim.
Takeaway: Same table, different recurrence — count instead of minimise.
Step zero
Discussion prompt
Verifying by listing every way to make 4 — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: List the combination that uses only 1's
Answer:
Worked example
List every combination of coins worth 1 and 2 that sums to exactly 4, to check the table's count of 3 directly.
List the combination that uses only 1's
Why: Four coins of value 1: 1 plus 1 plus 1 plus 1 is 4. That is one combination.
List the combination with exactly one coin of value 2
Why: One 2 and two 1's: 2 plus 1 plus 1 is 4. That is a second, distinct combination - the order the coins are listed in doesn't create new ones.
List the combination with two coins of value 2
Why: Two 2's: 2 plus 2 is 4. That is a third combination. No combination can use three or more 2's, since three 2's already sum to 6, exceeding 4.
Verify the count matches the table
Why: Exactly three distinct combinations were found - four 1's, one 2 with two 1's, and two 2's - matching the table's entry of 3 for amount 4 with coin types 1 and 2.
\[ 3 \text{ combinations} = dp[2][4] \]
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Verify the count matches the table
What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.
Hint: Every quantity in the result had to enter somewhere. Account for each one.
Answer:
List every combination of coins worth 1 and 2 that sums to exactly 4, to check the table's count of 3 directly.
Concept
You have a metal rod of a certain length and a price list telling you what each length of piece sells for. Cut the rod into any number of pieces, of any lengths that add up to the original length, to maximize total revenue.
| length | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| price | 1 | 5 | 8 | 9 | 10 |
We will trace a rod of length 5 with this exact price list through the rest of this section.
Intuition
Nothing stops a cut piece of length 2 from appearing twice in the same rod - pieces are just lengths, and every length is available as many times as the remaining rod allows.
That makes rod cutting an unbounded decision, like coin change, not a 0/1 decision like knapsack - there is no separate physical copy of each length to run out of.
Concept
The state is a single number: the length of rod still to be cut. Store the best total revenue obtainable from a rod of exactly that length.
\[ dp[\text{len}] = \text{best revenue from a rod of length len} \]
Concept
Instead of a take-or-skip choice, rod cutting asks: how long should the very first piece be? Try every possible length for that first piece, then solve the remaining rod the same way.
\[ dp[\text{len}] = \max_{1 \le i \le \text{len}} \big(\text{price}_i + dp[\text{len} - i]\big) \]
Because every remaining piece will also eventually be treated as 'the first piece' of what's left, this one formula automatically considers every possible way to split the whole rod.
Concept
Knapsack's state needed an item-index dimension because each item could be used at most once, and the recurrence had to remember how many items had already been considered.
Rod cutting has no such restriction - every length of first piece is available at every step, considered fresh each time - so the state only ever needs to track the length still remaining.
Picture it
Animation
Shows: Each row needs only the row above — a rendered Manim animation.
Rendered with Manim.
Takeaway: Which is why one array of length W is enough if you sweep the right way.
Concept
A rod with no length left to cut produces no pieces and no revenue. That is the one fact known before the recurrence runs.
\[ dp[0] = 0 \]
Explain it
Discussion prompt
Explain Base case: a zero-length rod earns nothing to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
A rod with no length left to cut produces no pieces and no revenue. That is the one fact known before the recurrence runs.
Concept
The table has one entry per rod length from 0 up to the original length, and filling each entry tries every shorter first-cut length.
\[ \text{time} = \Theta(n^2) \]
where n is the rod's original length, since the entry for length n tries up to n different first cuts.
\[ \text{space} = \Theta(n) \]
Analogy
Discussion prompt
Explain Time and space complexity of rod cutting by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
The table has one entry per rod length from 0 up to the original length, and filling each entry tries every shorter first-cut length.
Estimation
Predict first
Price list for lengths 1 through 5: 1, 5, 8, 9, 10. Fill dp[len] for len from 0 through 5.
Commit before you compute: what does Filling the rod-cutting table come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: Verify the final entry against a direct combination
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Cutting the rod into a piece of length 2 and a piece of length 3 gives revenue 5 plus 8, which is 13 - matching the table's final entry.
Worked example
Price list for lengths 1 through 5: 1, 5, 8, 9, 10. Fill dp[len] for len from 0 through 5.
| length | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| price | 1 | 5 | 8 | 9 | 10 |
Length 0 and 1
Why: Length 0 is the base case, worth 0. For length 1, the only first cut is length 1 itself: price 1 plus the length-0 entry, which is 1.
| len | 0 | 1 |
|---|---|---|
| dp[len] | 0 | 1 |
Length 2
Why: A first cut of length 1 gives price 1 plus the length-1 entry, or 2. A first cut of length 2 gives price 5 plus the length-0 entry, or 5. The whole-piece cut wins.
| len | 0 | 1 | 2 |
|---|---|---|---|
| dp[len] | 0 | 1 | 5 |
Length 3
Why: Length-1 first cut: price 1 plus the length-2 entry, or 6. Length-2 first cut: price 5 plus the length-1 entry, or 6. Length-3 first cut: price 8 plus the length-0 entry, or 8. Selling it whole wins.
| len | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| dp[len] | 0 | 1 | 5 | 8 |
Length 4
Why: Length-1: 1 plus 8 is 9. Length-2: 5 plus 5 is 10. Length-3: 8 plus 1 is 9. Length-4: 9 plus 0 is 9. Cutting off a length-2 piece first wins.
| len | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp[len] | 0 | 1 | 5 | 8 | 10 |
Length 5
Why: Length-1: 1 plus 10 is 11. Length-2: 5 plus 8 is 13. Length-3: 8 plus 5 is 13. Length-4: 9 plus 1 is 10. Length-5: 10 plus 0 is 10. The best is 13, tied between first cuts of length 2 and length 3.
| len | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[len] | 0 | 1 | 5 | 8 | 10 | 13 |
Verify the final entry against a direct combination
Why: Cutting the rod into a piece of length 2 and a piece of length 3 gives revenue 5 plus 8, which is 13 - matching the table's final entry. Selling the rod whole only earns 10, confirming that cutting is worth it here.
\[ dp[5] = 13 = 5 + 8 \]
Picture it
Animation
Shows: Each line of the worked example "Filling the rod-cutting table", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Cutting the rod into a piece of length 2 and a piece of length 3 gives revenue 5 plus 8, which is 13 - matching the table's final entry. Selling the rod whole only earns 10, confirming that cutting is worth it here.
Fill the middle
Fill in the blanks
From How to reconstruct the cuts — finish the line. Write what belongs on the right of the equals sign before you look.
\text\text{price}_i + dp[\text{len}-i] i \text___ dp[\text___] = ___
Why: Producing the right-hand side unprompted is the difference between recognising this line and being able to use it. Check every possible first-cut length from 1 up to the current length; the one where its price plus the remaining rod's best revenue equals the table entry is the one that was used.
Concept
Walk backward from the full rod length, at each step finding which first-cut length actually achieved the best revenue.
Find the winning first-cut length at the current length
Why: Check every possible first-cut length from 1 up to the current length; the one where its price plus the remaining rod's best revenue equals the table entry is the one that was used.
\[ \text{first cut } i \text{ used if } dp[\text{len}] = \text{price}_i + dp[\text{len}-i] \]
Record that piece length and move to the remaining rod length
Why: Subtract the chosen first-cut length from the current length and repeat the search there.
Stop once the remaining length reaches 0. Every piece length recorded is part of an optimal set of cuts.
Notation
Annotate
From How to reconstruct the cuts — read this one piece at a time. What is each part doing?
On: \( \text{first cut } i \text{ used if } dp[\text{len}] = \text{price}_i + dp[\text{len}-i] \)
Ranking
Put in order
Put the moves of Reconstructing the cuts for length 5 into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Length 1: price 1 plus the length-4 entry is 1 plus 10, or 11 - not a match.
Worked example
Use the filled table to walk back from length 5.
| len | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| dp[len] | 0 | 1 | 5 | 8 | 10 | 13 |
At length 5, test each first-cut length
Why: Length 1: price 1 plus the length-4 entry is 1 plus 10, or 11 - not a match. Length 2: price 5 plus the length-3 entry is 5 plus 8, or 13 - a match. Length 3 also matches, but the search follows the first match found.
\[ \text{first cut } 2 \text{ used; remaining length } 5-2=3 \]
At length 3, test each first-cut length
Why: Length 1: price 1 plus the length-2 entry is 1 plus 5, or 6 - not a match. Length 2: price 5 plus the length-1 entry is 5 plus 1, or 6 - not a match. Length 3: price 8 plus the length-0 entry is 8 plus 0, or 8 - a match.
\[ \text{first cut } 3 \text{ used; remaining length } 3-3=0 \]
Verify the recovered cuts
Why: The walk-back recorded pieces of length 2 and length 3, which sum to 5, the original rod length, and whose prices sum to 5 plus 8, or 13 - matching the table's final entry exactly.
\[ 2 + 3 = 5,\quad 5 + 8 = 13 = dp[5] \]
Intuition
What move should we make next?
Knapsack, coin change and rod cutting, all solved today.
For each one, say the subproblem sentence and the last decision, from memory, without scrolling back.
If you can produce all six from memory, you own the procedure. If you can only produce the recurrences, you memorized three answers.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Picture it
Animation
Shows: Every item poses one binary question — a rendered Manim animation.
Rendered with Manim.
Takeaway: Two branches per item, and the table stops it becoming two to the n.
Concept
All three problems share the same skeleton - state, recurrence, base case, fill order, reconstruction - but differ in exactly how many times each choice can be used.
| problem | state | choice type | table shape |
|---|---|---|---|
| 0/1 knapsack | items considered, capacity | take at most once | 2 dimensions |
| minimum coins | amount | take any number of times | 1 dimension |
| counting ways | coin types considered, amount | take any number of times | 2 dimensions |
| rod cutting | length remaining | take any number of times | 1 dimension |
Discrimination
Sort into buckets
Sort these by choice type, from memory, without looking back at Comparing the three setups side by side. Telling them apart on the spot is the skill; the table is only where the answer happens to be written down.
Intuition
Every entry in a correctly filled table is a small, already-proven fact - the best value, count, or revenue for a smaller version of the same problem. Reading the final cell is not a guess; it is the last link in a chain of facts you built yourself.
That is why filling the table in the right order matters so much: every cell must only ever look at cells that are already known facts, never at a cell still waiting to be filled.
Pattern
1. Define the state in plain words
Why: Name exactly what a table entry represents before writing any formula - what is fixed, and what does the entry store?
2. Write the recurrence: what are the actual choices?
Why: Enumerate every option for extending a solution - skip versus take once, or try every possible last coin or first cut - and combine them with a max, min, or sum, whichever the problem asks for.
3. Pin down the base case
Why: Identify the smallest instance whose answer is obvious without any recurrence, and start filling from there.
4. Choose a fill order that respects the dependencies
Why: Every cell must only depend on cells already filled - the row above for 0/1 choices, the same row for unbounded ones.
5. Plan the reconstruction alongside the recurrence
Why: At each cell, know how to tell which choice produced its value, so the actual items, coins, or cuts can be recovered by walking backward, not just their count.
Real world
Discussion prompt
Outside this lesson: where does Dynamic Programming II: Knapsack, Coin Change & Rod Cutting actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of The five-step DP setup recipe is doing the work in it.
Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.
Answer:
0/1 knapsack, minimum-coin and combination-counting coin change, and rod cutting, taught with the setup made explicit every time: define the state in words, write the take-or-skip (or best-choice) recurrence, pin the base case, fill the table in dependency order, and reconstruct the actual items, coins, or cuts chosen. Targets four real misconceptions: using a best-ratio greedy strategy on 0/1 knapsack, accidentally reusing a single-copy item, using a greedy coin heuristic on a coin system where it overshoots the true minimum, and an off-by-one in the table's capacity or amount dimension.
Check
Consider one cell of a 0/1 knapsack table. The item under consideration has weight 4 and value 6. The remaining capacity at this cell is 3.
Check your understanding
What must this table entry equal?
Answer: A
Why: Weight 4 is larger than the remaining capacity of 3, so the take branch is not a legal option here - it would require negative remaining capacity. The only legal value is copying the entry directly above, at the same capacity.
Elimination
Eliminate the wrong options
What does the correct 0/1 knapsack answer give for capacity 10?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: Item 2 alone weighs 10 and fits exactly in capacity 10, earning value 50 - more than item 1's 30. Checking every subset, not just the ratio order, is what the 0/1 recurrence does automatically, and it finds 50 is optimal.
Check
Two items: weight 5, value 30; and weight 10, value 50. Capacity 10. Greedy by ratio picks the first item only (it fits, leaving 5, and the second item needs 10, which no longer fits), for a total of 30.
\[ \text{item 1: weight 5, value 30}\quad\text{item 2: weight 10, value 50} \]
Check your understanding
What does the correct 0/1 knapsack answer give for capacity 10?
Answer: A
Why: Item 2 alone weighs 10 and fits exactly in capacity 10, earning value 50 - more than item 1's 30. Checking every subset, not just the ratio order, is what the 0/1 recurrence does automatically, and it finds 50 is optimal.
Prediction
Predict first
What is the fewest coins needed to make amount 5?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: 2, using a 4 and a 1.
Why: The amount-5 entry equals the minimum of trying each coin last: 1 plus the amount-4 entry, 1 plus the amount-2 entry, or 1 plus the amount-1 entry, which works out to 2, 3, and 2. The minimum, 2, is achieved by combining a 4 and a 1, which sum to 5.
Check
Coins available: 1, 3, and 4, in unlimited supply.
Check your understanding
What is the fewest coins needed to make amount 5?
Answer: A
Why: The amount-5 entry equals the minimum of trying each coin last: 1 plus the amount-4 entry, 1 plus the amount-2 entry, or 1 plus the amount-1 entry, which works out to 2, 3, and 2. The minimum, 2, is achieved by combining a 4 and a 1, which sum to 5.
Commit first
Predict first
How many distinct combinations of coins worth 1 and 2 sum to exactly 3?
Commit to an answer, then rate it — certain, fairly sure, or guessing — and write the rating down before you turn the page.
Correct: 2, the combinations of three 1's, and one 1 with one 2.
Why: There are exactly two combinations of 1's and 2's that sum to 3: three 1's, or one 1 plus one 2. Order doesn't matter, so listing the 1 first or the 2 first counts as the same combination, matching the table's entry of 2 for amount 3.
The rating matters as much as the answer: confident-and-wrong is the combination that survives revision, because nothing about it feels like it needs revisiting.
Check
Coin types available: value 1 and value 2, in unlimited supply.
Check your understanding
How many distinct combinations of coins worth 1 and 2 sum to exactly 3?
Answer: A
Why: There are exactly two combinations of 1's and 2's that sum to 3: three 1's, or one 1 plus one 2. Order doesn't matter, so listing the 1 first or the 2 first counts as the same combination, matching the table's entry of 2 for amount 3.
Prediction
Predict first
What is the best obtainable revenue for a rod of length 4, and how is it achieved?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: 10, by cutting a first piece of length 2 and using the best revenue for the remaining length-2 rod.
Why: The length-4 entry is the maximum over every first-cut length: 1 plus the length-3 entry, 5 plus the length-2 entry, 8 plus the length-1 entry, or 9 plus the length-0 entry, giving 9, 10, 9, and 9. The maximum, 10, comes from a first cut of length 2 combined with the best revenue from the remaining length-2 rod, which is itself a single piece of length 2.
Check
Price list: lengths 1 through 5 sell for 1, 5, 8, 9, and 10. Consider a rod of length 4.
| length | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| price | 1 | 5 | 8 | 9 | 10 |
Check your understanding
What is the best obtainable revenue for a rod of length 4, and how is it achieved?
Answer: A
Why: The length-4 entry is the maximum over every first-cut length: 1 plus the length-3 entry, 5 plus the length-2 entry, 8 plus the length-1 entry, or 9 plus the length-0 entry, giving 9, 10, 9, and 9. The maximum, 10, comes from a first cut of length 2 combined with the best revenue from the remaining length-2 rod, which is itself a single piece of length 2.
Elimination
Eliminate the wrong options
How many entries should the table have, from the smallest amount up to the target?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: The table must hold one entry for every amount from 0 up to and including the target, 8. That is 8 minus 0 plus 1, or 9 entries. Leaving out amount 0 or amount 8 removes either the base case or the final answer itself.
Check
You are filling a minimum-coins table for a target amount of 8.
Check your understanding
How many entries should the table have, from the smallest amount up to the target?
Answer: A
Why: The table must hold one entry for every amount from 0 up to and including the target, 8. That is 8 minus 0 plus 1, or 9 entries. Leaving out amount 0 or amount 8 removes either the base case or the final answer itself.
Concept
Moves added today: none.
That is a result, not a gap. Everything in this lesson was proved with moves you already owned.
Moves you reused today:
Three different problems today, one procedure. The only thing that changed between knapsack, coin change and rod cutting was the sentence in step 1 and the last decision in step 2.
Full toolkit so far: #1 through #13.
Next session opens with you naming every one of these from memory, before any new material.
Counterexample
Discussion prompt
Three different problems today, one procedure. The only thing that changed between knapsack, coin change and rod cutting was the sentence in step 1 and the last decision in step 2.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
Next session opens with you naming every one of these from memory, before any new material.
Picture it
Animation
Shows: Why greedy fails on 0/1 knapsack — a rendered Manim animation.
Rendered with Manim.
Takeaway: The best ratio is not the best set.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — The five-step DP setup recipe · Toolkit check-in: name them before you look · Two ingredients every DP needs · The 0/1 knapsack problem · Why it's called 0/1. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
You now have the setup habit that makes any new DP problem tractable: define the state in words, write the recurrence as an explicit choice, pin down the base case, fill in dependency order, and plan the reconstruction from the start.
| Technique | The one move |
|---|---|
| 0/1 knapsack | max of skip vs. take, row above only |
| Minimum coins | min over every coin tried last |
| Counting ways | sum of without-this-coin and with-this-coin |
| Rod cutting | max over every possible first-cut length |
Want this taught 1-on-1? Alexander tutors CS3000 Algorithms — $55/session, free consultation.