Given coin denominations, make a target amount. Three distinct questions, three different recurrences — mixing them up is the most common error in this family.
1. Minimum number of coins
vector<int> dp(W + 1, INT_MAX);
dp[0] = 0;
for (int w = 1; w <= W; w++)
for (int c : coins)
if (c <= w && dp[w - c] != INT_MAX)
dp[w] = min(dp[w], dp[w - c] + 1);. Order of the loops does not matter here.
2. Number of combinations (order does not matter)
Coins on the outside, amount on the inside:
vector<long long> dp(W + 1, 0);
dp[0] = 1;
for (int c : coins) // coin loop OUTSIDE
for (int w = c; w <= W; w++)
dp[w] += dp[w - c];Each coin type is fully processed before the next, so and are never both counted.
3. Number of permutations (order matters)
Amount on the outside, coins on the inside:
vector<long long> dp(W + 1, 0);
dp[0] = 1;
for (int w = 1; w <= W; w++) // amount loop OUTSIDE
for (int c : coins)
if (c <= w) dp[w] += dp[w - c];The loop order is the semantics
Identical bodies, swapped loops, completely different answers. For target 3 with coins : combinations gives 2 (, ); permutations gives 3 (, , ). Read the statement carefully.
When greedy works
Greedy (always take the largest coin that fits) is not generally optimal: with coins and target 6, greedy gives coins but the optimum is .
A coin system where greedy is always optimal is called canonical. Real currencies (including all common ones) are canonical, which is why the wrong intuition persists. Deciding whether a system is canonical is itself an interesting problem — Pearson’s algorithm does it in by checking a bounded set of counterexample candidates.
Never assume greedy unless the problem states the denominations and you have verified them.
The variants
| Question | Recurrence |
|---|---|
| Minimum coins | |
| Number of combinations | coins outside, dp[w] += dp[w-c] |
| Number of permutations | amount outside |
| Is amount reachable? | boolean; use a bitset for |
| Each coin used at most once | 0/1 knapsack — weight loop downward |
| Each coin used at most times | bounded knapsack — binary splitting or monotone queue |
| Maximum coins with a value limit | knapsack with values |
| Which coins were used | store a from[w] array and walk back |
| Huge , small coins | matrix exponentiation on the linear recurrence, or the Chicken McNugget / Frobenius structure |
| Count solutions modulo | same DP, take everything mod |
The Frobenius / Chicken McNugget number
With two coprime coins , the largest amount not representable is
and exactly amounts are unrepresentable. For three or more coins there is no closed form, and computing the Frobenius number is NP-hard in general — though for small coin values a shortest-path formulation works:
Build a graph on residues mod ; edge from to with weight . The shortest distance to residue is the smallest representable amount congruent to . This “coin graph” / Dijkstra on residues technique answers “is representable” for up to in .
That trick is genuinely useful and worth remembering: when the target is astronomically large but the smallest coin is small, work modulo the smallest coin.
Related
- Classical Problems — the puzzle framings of the same question
- Knapsack — the general framework
- Subset Sum — the 0/1 feasibility version
- Generating functions — the counting version is the coefficient of in
See also: Knapsack · Partition Problems · Generating Functions