Dynamic Programming: Complete Knapsack Problems - Climbing Stairs, Coin Change, and Perfect Squares

Climbing Stairs (Advanced)

This problem extends the classic climbing stairs by allowing jumps of any length, making it equivalent to a complete knapsack permutation problem.

Problem (Kamangar 57): Given m available step sizes, determine how many ways to reach stair n.

Dynamic Programming Approach

1. DP Array Definition: dp[j] represents the number of ways to reach step j.

2. Recurrence Formula: dp[j] accumulates the ways from previous positions:

dp[j] += dp[j - step];

3. Initialization: dp[0] = 1 (one valid way to stay at ground level).

4. Traversal Order: For permutation problems, iterate背包 first (outer loop), then items (inner loop). Complete knapsack uses forward traversal.

Key Point: Always validate before updating the recurrence formula in complete knapsack permutation scenarios.

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int steps, target;
    while (cin >> target >> steps) {
        vector<int> dp(target + 1);
        dp[0] = 1;
        for (int j = 1; j <= target; j++) {
            for (int k = 1; k <= steps; k++) {
                if (j >= k) {
                    dp[j] += dp[j - k];
                }
            }
        }
        cout << dp[target];
    }
    return 0;
}

Coin Change

Leetcode 322: Given coin denominations, find the minimum coins needed to make up a target amount.

Solution

1. DP Array: dp[j] = minimum coins required to reach amount j.

2. Recurrence:

dp[j] = min(dp[j], dp[j - coin] + 1);

3. Initialization: dp[0] = 0; all other positions set to INT_MAX.

4. Traversal: Outer loop iterates coins; inner loop traverses amounts forward (complete knapsack).

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1, INT_MAX);
        dp[0] = 0;
        
        for (int coin : coins) {
            for (int j = coin; j <= amount; j++) {
                if (dp[j - coin] != INT_MAX) {
                    dp[j] = min(dp[j], dp[j - coin] + 1);
                }
            }
        }
        
        return dp[amount] == INT_MAX ? -1 : dp[amount];
    }
};

Critical Check: The condition dp[j - coin] != INT_MAX prevents overflow when certain amounts cannot be formed.


Perfect Squares

Leetcode 279: Given integer n, find the minimum number of perfect squares that sum to n.

This problem mirrors coin change, where each perfect square (1, 4, 9, 16...) serves as a "coin."

Solution

1. DP Array: dp[j] = minimum perfect squares needed to sum to j.

2. Recurrence:

dp[j] = min(dp[j], dp[j - square] + 1);

where square = i * i.

3. Initialization: dp[0] = 0; remaining entries initialized to INT_MAX.

4. Traversal: Outer loop generates valid squares; inner loop processes amounts forward.

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        
        for (int i = 1; i * i <= n; i++) {
            int square = i * i;
            for (int j = square; j <= n; j++) {
                if (dp[j - square] != INT_MAX) {
                    dp[j] = min(dp[j], dp[j - square] + 1);
                }
            }
        }
        return dp[n];
    }
};

Note: Since 1 is always a perfect square, every positive integer can be represented—this guarantees a valid solution exists.

Tags: Dynamic Programming complete knapsack Permutations coin change perfect squares

Posted on Fri, 30 Oct 2026 16:21:01 +0000 by cmos