目录
题目链接:70. 爬楼梯 (进阶)
思路
代码
题目链接:322. 零钱兑换
思路
代码
题目链接:279.完全平方数
思路
代码
总结
题目链接:70. 爬楼梯 (进阶)
思路
依旧是转换成背包问题,每次能爬的阶数就是物品,且物品可以重复使用,例如爬完一阶,可以再爬一阶,而背包则是楼梯的总阶数,这样就是完全背包问题了。
①dp数组,dp[j]表示爬j阶楼梯时有dp[j]种方法
②递推数组,dp[j] += dp[j-i]
③dp数组初始化,dp[0] = 1,其余为0
④遍历顺序,先背包后物品,按照题意求的是排列数
⑤推导dp数组
代码
#include <iostream>
#include <vector>
using namespace std;
int main() {int n, m; // n是总台阶数,m是一次至多爬m阶while (cin >> n >> m) {vector<int> dp(n + 1, 0);dp[0] = 1;// 先背包后物品,求排列数for (int j = 1; j <= n; j++) {for (int i = 1; i <= m; i++) {if (j >= i) {dp[j] += dp[j - i];}}}cout << dp[n];}
}
题目链接:322. 零钱兑换
思路
硬币无限使用,完全背包问题。求的是最小硬币数,所以递推公式更新的是最小值
①dp数组,dp[j]表示总金额为j时可以兑换最少的硬币数
②递推公式,dp[j] = min(dp[j-coins[i]]+1, dp[j])
③dp数组初始化,dp[0] = 0,其余为int最大值,因为递推公式更新的是最小值
④遍历顺序,本题求的是商品数量的最小值,所以排列和组合都一样
⑤推导dp数组
代码
class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);dp[0] = 0;for (int i = 0; i < coins.size(); i++) {for (int j = coins[i]; j <= amount; j++) {// 若dp[j - coins[i]为初始值,跳过if (dp[j - coins[i]] != INT_MAX) {dp[j] = min(dp[j - coins[i]] + 1, dp[j]);}}}if (dp[amount] == INT_MAX)return -1;return dp[amount];}
};
题目链接:279.完全平方数
思路
①dp数组,dp[j]表示和为j的完全平方数的最小个数为dp[j]
②递推公式,dp[j] = min(dp[j-(i*i)]+1,dp[j])
③dp数组初始化,dp[0] = 0,其余为int最大值
④遍历顺序,与322.零钱兑换类似,只求最小个数,排列组合一样
⑤推导dp数组
代码
class Solution {
public:int numSquares(int n) {vector<int> dp(n + 1, INT_MAX);dp[0] = 0;// 先物品,后背包// i*i<=n时说明物品重量没有超过背包for (int i = 1; i * i <= n; i++) {for (int j = i * i; j <= n; j++) {// j从i*i开始,保证当前的商品可以放进背包dp[j] = min(dp[j - (i * i)] + 1, dp[j]);}}return dp[n];}
};
总结
①完全背包问题的应用:求装满背包时最大的商品数量,最小的商品数量
②当不确定与排列组合有没有关系时,选相同的结果进行举例,例如{1,2}和{2,1}有无区别
③完全背包与01背包相比,少了商品数量的限制,好像更简单一点