03
Unbounded (DP — Knapsack Sub-pattern)
Items can be used any number of times. The capacity loop goes low → high so a cell can build on itself.
Signals in the problem statement
- ›
"unlimited supply of each coin"
- ›
"fewest coins to make the amount"
- ›
"number of combinations / orders that add up to target"
What makes it different
Forward loop. For counting, items-outer counts combinations (1 + 2 = 2 + 1), amount-outer counts orders (1 + 2 and 2 + 1 are different).
Questions
ordered from “learn the idea” to “recognise it without help”- 1Knapsack with Duplicate ItemsWalkthroughMediumBasic Anchor·GeeksforGeeks
- 2Coin ChangeWalkthroughMediumBasic Reinforcement·LeetCode #322
- 3Coin Change IIWalkthroughMediumSlight Variation·LeetCode #518
- 4Combination Sum IVWalkthroughMediumPattern Transfer·LeetCode #377
Template
unbounded-template.cpp
// Unbounded: items can repeat, so the amount goes LOW -> HIGH
// (dp[a - c] may already use coin c, which lets it be used again).
// Fewest coins to make the amount (-1 if impossible).
int minCoins(const vector<int>& coins, int amount) {
const int INF = amount + 1;
vector<int> dp(amount + 1, INF);
dp[0] = 0;
for (int c : coins)
for (int a = c; a <= amount; a++)
dp[a] = min(dp[a], dp[a - c] + 1);
return dp[amount] >= INF ? -1 : dp[amount];
}
// Count ways. Coins outer -> combinations; amount outer -> ordered sequences.
long long countCombinations(const vector<int>& coins, int amount) {
vector<long long> dp(amount + 1, 0);
dp[0] = 1;
for (int c : coins)
for (int a = c; a <= amount; a++) dp[a] += dp[a - c];
return dp[amount];
}Remember this · DP — Knapsack
Trigger
Pick a subset to hit a target sum / capacity, partition into two groups, count the ways to reach an amount.
Think
Is this "choose some items so their total is X"?
Key question
Can each item be used once (loop capacity backwards) or many times (loop forwards)?