学习资料:代码随想录
这一块儿学得挺痛苦
注:文中含大模型生成内容
动态规划:01背包理论基础
思路:五部曲
定义:dp[i][j]为第i个物品背包容量为j,能装下的最大价值
递推公式:dp[i][j]的值等于dp[i-1][j]的值和dp[i-1][j-weight[i]]+value相比的最大值,后者为看放下当前物品+减去当前物品的容量能放下什么价值,当然,要是放不下当前物品,就算了,保持原来的值把
初始化:左边(dp[i][0]背包容量为0)都初始化为0,挺好的,就是不用管了
dp[0][j],容量j能把物品0放上就放上,放不上就是0
遍历顺序:怎么着都行
打印:略
cpp
#include <bits/stdc++.h>
using namespace std;
int main(){
int materials,N;
cin>>materials>>N;
vector<int> space(materials,0);
for(int i=0;i<materials;i++){
cin>>space[i];
}
vector<int> value(materials,0);
for(int i=0;i<materials;i++){
cin>>value[i];
}
vector<vector<int>> dp(materials,vector<int>(N+1,0)); //dp[i][j]表示有i个材料可以放,背包能装的空间为j时的最大价值,从行李空间为0开始递推
for(int j=space[0];j<=N;j++) dp[0][j] = value[0];
for(int i=1;i<materials;i++){ //i从1开始,否则在递推函数处会索引负数
for(int j=0;j<=N;j++){
if(j<space[i]) dp[i][j] = dp[i-1][j]; //防止下面出现负索引
else{
dp[i][j] = max(dp[i-1][j],dp[i-1][j-space[i]]+value[i]); //递推公式得画图模拟一下
}
}
}
cout << dp[materials-1][N]<<endl; //第materials个物品下标为materials-1
}
动态规划:01背包理论基础(滚动数组)
滚动数组是把原先的二维dp数组压缩成一维了,就等于看新一个物品能不能装上的时候就按规矩累计之前的结果然后把之前的覆盖掉
主要在遍历方向上很难:
一是j要倒着遍历:
TA说得很清楚:二维是根据上一个物品更新的。而一维数组是在本行根据本物品更新的。正序的化就会产生能多次放该物品的错觉,实际上该物品只能放一次

为什么不能先遍历背包,还是让TA帮我模拟一下,不行啊,先遍历背包的话只能加上一个物品。

啊,这不就是我的贾维斯吗!!我能获得一份开发贾维斯的工作吗
我自己模拟了一下正向遍历j在外层,不行,会出现重复放一个物品的问题。总之,根据递推公式来看,还是要提取上一轮的信息,不要让上一轮的信息被本轮信息覆盖
416. 分割等和子集
思路:关键在于如何将其转换为背包问题;
dp[j]为背包容量为j,能装的最大价值,那么在这里,,value[i]和weight[i]都是nums[i];背包容量是数字和的一半sum/2,是那个target,如果背包容量target能装target,就是能对半儿分了
cpp
// 五部曲
// dp定义:dp[j] 容量为j的背包,能装的价值为dp[j]
// 递推公式:按背包来,价值和重量都是这个数的值
// 初始化:根据递推公式的max要选最大的,nums都是正整数,所以都初始化为最小的正整数0
// 遍历顺序:按背包来
// 打印
class Solution {
public:
bool canPartition(vector<int>& nums) {
vector<int> dp(100*200/2+1); //根据题意区间写的
int sum = 0;
for(int num:nums){
sum+=num;
}
if (sum%2!=0) return false;
int target = sum/2;
for(int i=0;i<nums.size();i++){
for(int j=target;j>=nums[i];j--){
dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
return dp[target] == target;
}
};
https://www.youtube.com/watch?v=bI_GJHCePlY今日发现一件艺术品,搁5、6年前我可能是他们的受众,现在的我没有耐心连着看第三遍了。Anyway,祝大家今晚睡个好觉,明天是Sunday Morning哦