2Brute2Best
🔥0
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”
  1. 1
    Knapsack with Duplicate Items
    Basic Anchor·GeeksforGeeks
    Medium
  2. 2
    Coin Change
    Basic Reinforcement·LeetCode #322
    Medium
  3. 3
    Coin Change II
    Slight Variation·LeetCode #518
    Medium
  4. 4
    Combination Sum IV
    Pattern Transfer·LeetCode #377
    Medium

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)?