Day 45 动态规划 7

70. 爬楼梯

代码随想录

1. 思路

不难看出,这道题是一个完全背包计数问题,因为是排列(131和113是两种),因此背包遍历在外循环,物品遍历在内循环。 

#include 
#include 
using namespace std;
int main() {
    int n, m;
    while (cin >> n >> m) {
        vector dp(n + 1, 0);
        dp[0] = 1;
        for (int i = 1; i <= n; i++) { // 遍历背包
            for (int j = 1; j <= m; j++) { // 遍历物品
                if (i - j >= 0) dp[i] += dp[i - j];
            }
        }
        cout << dp[n] << endl;
    }
}

322. 零钱兑换

代码随想录

1. 思路

这道题是典型的完全背包问题(均正序),但是dp数组更新的方式不同:

dp[j] = min(dp[j], dp[j-coins[i]]+1)

由于钱币对于结果没有影响(我们要找的是最小个数,并非计数),因此使用先元素再背包的遍历方法或者反之都可以。

 比较特殊的是初始化方法,可以考虑0代表什么含义(确认[0],以及第一轮(第一个物品)该如何初始化(确认其他位置)。dp[0]代表在总金额为0的情况下,凑齐的钱币个数,应该是0。而其他的地方可以初始化为maxint。这样在第一轮的时候,会在第一个钱币的整数位呈现阶梯跳跃的情况,如(假设第一个钱币位4)0 m m m 1 m m m 2 m m ...

// 版本一
class Solution {
public:
    int coinChange(vector& coins, int amount) {
        vector dp(amount + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i < coins.size(); i++) { // 遍历物品
            for (int j = coins[i]; j <= amount; j++) { // 遍历背包
                if (dp[j - coins[i]] != INT_MAX) { // 如果dp[j - coins[i]]是初始值则跳过
                    dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
                }
            }
        }
        if (dp[amount] == INT_MAX) return -1;
        return dp[amount];
    }
};

279. 完全平方数

代码随想录

1. 思路

这道题比上一题(完全背包取最小值)更进一步,需要自己定义元素。我当时的想法是,直接先定义所有的可能元素,之后转化为背包问题。但其实可以更简单,因为元素一定要小于限制才有用,因此j和i有关。而因为顺序对结果没有影响,因此可以先遍历背包,之后根据背包限制住可以遍历的元素,不用事先定义

// 版本一
class Solution {
public:
    int numSquares(int n) {
        vector dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i <= n; i++) { // 遍历背包
            for (int j = 1; j * j <= i; j++) { // 遍历物品
                dp[i] = min(dp[i - j * j] + 1, dp[i]);
            }
        }
        return dp[n];
    }
};

你可能感兴趣的:(算法)