第九章 动态规划part03
2026.03.20 03.07 第三十九天
46 携带研究材料
二维背包问题,01背包
最基础的01背包问题,之前没有遇到过,看了很久才看懂,最重要的是推导出递推公式,还有边界值的初始化~
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
int main() {
int n, bagWight;
cin >> n >> bagWight;
vector<int> weight(n, 0);
vector<int> value(n, 0);
for(int& i : weight) cin >> i;
for(int& j : value) cin >> j;
vector<vector<int>> dp(n, vector<int>(bagWight + 1, 0));
for(int j = weight[0]; j < dp[0].size(); j++) {
dp[0][j] = value[0];
}
for(int i = 1; i < dp.size(); i++) {
for(int j = 0; j < dp[0].size(); j++) {
if(j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[dp.size() - 1][dp[0].size() - 1];
}
46 携带研究材料
将二维数组压缩成了一维数组
对应的递推式也发生了变化
要注意当前还没有更新值的数组值就是i-1对应的数组值,又因为当前递推式只依赖i-1的状态,因此可以进行压缩
由于从前往后放会导致同一物品被放入多次,因此要从后往前放!!!
从递推关系式可知,一维数组所有值初始化为0即可
有一点理解难度,不过是从1到2,而不是零基础接触背包问题的从0到1;
for (int j = dp.size(); j >= weight[i]; j--)保证了j - weight[i]不会越界成为负数!
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
int main() {
int n, bagWight;
cin >> n >> bagWight;
vector<int> weight(n, 0);
vector<int> value(n, 0);
for(int& i : weight) cin >> i;
for(int& j : value) cin >> j;
vector<int> dp(bagWight + 1, 0);
for(int i = 0; i < n; i++) {
for(int j = dp.size(); j >= weight[i]; j--) {
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[dp.size() - 1];
}
416 分割等和子集
非常巧妙,把分割子集问题转化为从nums中挑选一些数字,把nums中数字之和的一半装满,就说明能够分成和相等的两半,如此一来问题就和上一题完全一致了。
nums要先进行排序。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
for(int& i : nums) sum += i;
if(sum % 2) return false;
sum /= 2;
sort(nums.begin(), nums.end());
vector<int> dp(sum + 1, 0);
for(int i = 0; i < nums.size(); i++) {
for(int j = dp.size() - 1; j >= nums[i]; j--) {
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
if(dp[dp.size() - 1] == sum) return true;
return false;
}
};

浙公网安备 33010602011771号