代码随想录算法训练营第32天|完全背包理论基础-二维DP数组、518.零钱兑换II、377. 组合总和 Ⅳ、57. 爬楼梯(进阶版)
卡码网52
2025-03-05 17:12:34 星期三
题目描述:卡玛网52
文档讲解:代码随想录(programmercarl)完全背包理论基础-二维DP数组
视频讲解:带你学透完全背包问题! 和 01背包有什么差别?遍历顺序上有什么讲究?
代码随想录视频内容简记
要点
-
完全背包和01背包的区别就是完全背包中对物品是可以重复取的,也就是不限制物品的数量。
-
在之前的一维滚动数组中,我们为了防止对物品重复取多次所以采用了后序遍历,那么在此基础上,只要改成前序即可变为完全背包
-
同时在遍历顺序中,完全背包因为该成了前序,所以实际上无论是先遍历背包还是先遍历物品都可以。当然也只是针对于纯完全背包问题
卡玛网测试
和之前的46基本一摸一样,稍作改动即可
另外需要注意的一点是在初始化的时候别初始化错了,vector<int> dp(bagweight + 1, 0);
,需要有一个+1的操作
点击查看代码
# include<iostream>
# include<vector>
using namespace std;
int main() {
int n, bagweight;
cin >> n >> bagweight;
vector<int> weight(n, 0);
vector<int> value(n, 0);
for (int i = 0; i < n; i++) {
cin >> weight[i] >> value[i];
}
vector<int> dp(bagweight + 1, 0);
for (int i = 0; i < n; i++) {
for (int j = 0; j <= bagweight; j++) {
if (j < weight[i]) dp[j] = dp[j];
else dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[bagweight] << endl;
return 0;
}
LeetCode518
题目描述:力扣518
文档讲解:代码随想录(programmercarl)518.零钱兑换II
视频讲解:《代码随想录》算法视频公开课:装满背包有多少种方法?组合与排列有讲究!| LeetCode:518.零钱兑换II
代码随想录视频内容简记
这道题和目标和那道题是很相似的,其实核心都是求装满背包有多少种方式。区别就在于本题可以一个物品使用多次,所以是一个完全背包问题。
梳理
-
确定dp[j]数组的含义,表示容量为j的背包,可以装满不同物品的组合数有dp[j]个
-
确定递推公式,
dp[j] += dp[j - coins[i]]
,和494目标和一样 -
初始化dp数组,dp[0] = 1,同样,这里如果为0,后面在进行计算的时候
dp[1 - 1] = 0,dp[2 - 2] = 0
,就都是0了 -
确定遍历顺序。本题需要求得是一个组合数,需要先遍历物品,后便利背包。而不是一个排列数,先遍历背包,后便利物品。
有什么区别呢?举个例子:
比如一个coins数组[1, 2],先遍历物品,后便利背包,那么在计算其重量永远都只会是{1, ..., 2},这样,就是1完了才会有2,所以是一个组合数。但如果先遍历背包,再遍历物品,其重量就会是{1...2, 1...2, 1...}会有重复产生,导致出现排列数
-
打印dp数组
LeetCode测试
注意这里有一个小细节,就是第28个测试用例会整数超出,所以在定义dp的时候用这个vector<uint64_t> dp(amount + 1, 0);
点击查看代码
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<uint64_t> dp(amount + 1, 0);
dp[0] = 1;
// if (amount < 0) return 0;
for (int i = 0; i < coins.size(); i++) {
for (int j = 0; j <= amount; j++) {
if (j < coins[i]) dp[j] = dp[j];
else dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
};
LeetCode377
题目描述:力扣377
文档讲解:代码随想录(progrmmercarl)377. 组合总和 Ⅳ
视频讲解:《代码随想录》算法视频公开课:装满背包有几种方法?求排列数?| LeetCode:377.组合总和IV
这道题和上面的518一摸一样,就是球的是一个排列数,所以先遍历背包,后便利物品即可。
LeetCode测试
点击查看代码
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<uint64_t> dp(target + 1, 0);
dp[0] = 1;
for (int j = 0; j <= target; j++) {
for (int i = 0; i < nums.size(); i++) {
if (j < nums[i]) dp[j] = dp[j];
else dp[j] += dp[j - nums[i]];
}
}
return dp[target];
}
};
57. 爬楼梯(进阶版)
题目描述:卡玛网57
文档讲解:代码随想录(programmercarl)57. 爬楼梯(进阶版)
梳理
这个题之前k哥在讲力扣70爬楼梯的时候提到过
-
本题可以将一次爬的台阶个数m抽象成物品的价值(同时也是物品的重量),n阶楼梯就可以抽象成背包的容量target
-
本题的物品的价值和重量的数组都是一样的,只需要从1到m添加到一个数组即可。
-
同时需要注意的是,本题仍然求的是一个排列数问题,需要先遍历背包,再遍历物品
卡玛网测试
点击查看代码
# include<iostream>
# include<vector>
using namespace std;
int main() {
int n, target;
cin >> target >> n;
vector<int> steps(n, 0);
for (int i = 0; i < n; i++) {
steps[i] = i + 1;
}
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int j = 0; j <= target; j++) {//先遍历背包
for (int i = 0; i < n; i++) {//再遍历物品
if (j < steps[i]) dp[j] = dp[j];
else dp[j] += dp[j - steps[i]];
}
}
cout << dp[target] << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端