【算法/动态规划/01背包】题解+详细备注(共4题)
01背包模板
使用二维数组
- 确定dp数组以及下标的含义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
- 确定递推公式:
- 不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同。)
- 放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值
- 所以递归公式:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
- 先遍历物品,再遍历背包
for(int i = 1; i < weight.size(); i++) {
for(int j = 0; j <= bagweight; 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]);
}
}
- 先遍历背包,再遍历物品
for(int j = 0; j <= bagweight; j++) {
for(int i = 1; i < weight.size(); i++) {
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]);
}
}
使用一维数组
- 确定dp数组以及下标的含义:dp[j]表示容量为j的背包,所背的物品价值可以最大为dp[j]
- 确定递推公式:
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
for(int i = 0; i < weight.size(); i++) {
for(int j = bagWeight; j >= weight[i]; j--) {
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
class Solution {
public:
bool canPartition(vector<int>& nums) {
int nSum = accumulate(nums.begin(),nums.end(),0);
if(nSum%2 == 1) return false;
int target = nSum/2;
vector<int> dp(target+1);
for(int i{};i<nums.size();++i){
for(int j = target;j>=nums[i];--j){
dp[j] = max(dp[j-nums[i]] + nums[i],dp[j]);
}
}
return dp[target] == target;
}
};
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
vector<int> dp(15001);
int targetSum = accumulate(stones.begin(),stones.end(),0);
int target = targetSum/2;
for(int i{};i<stones.size();++i){
for(int j = target;j>=stones[i];j--){
dp[j]=max(dp[j],dp[j-stones[i]] + stones[i]);
}
}
return targetSum - dp[target] - dp[target];
}
};
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int tSum = accumulate(nums.begin(),nums.end(),0);
if(abs(target) > tSum) return 0; ?/
tSum+=target;
if(tSum%2) return 0;
int target1 = tSum/2;
vector<int> dp(target1+1);
dp[0] = 1;
for(int i{};i<nums.size();++i){
for(int j = target1;j>=nums[i];--j){
dp[j] += dp[j-nums[i]];
}
}
return dp[target1];
}
};
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m+1,vector<int>(n+1));
for(int i{};i<strs.size();++i){
int oneNum{},zeroNum{};
for(char &c : strs[i]){
if(c == '0') zeroNum++;
else if(c == '1') oneNum++;
}
for(int j = m;j>=zeroNum;--j){
for(int k = n;k>=oneNum;--k){
dp[j][k] = max(dp[j][k],dp[j-zeroNum][k-oneNum] + 1);
}
}
}
return dp[m][n];
}
};
|