代码随想录算法训练营第三十五天(20250303) |01背包问题 二维,01背包问题 一维,416. 分割等和子集 -[补卡20250316]

01背包问题 二维

链接

  1. 遍历物品没有大小顺序要求
  2. 重点是模拟,推导出递推公式
#include 
#include 

int main(){
    int m, n;
    std::cin>>m>>n;
    std::vector weight(m,0),value(m,0);
    for(int i{0}; i>weight[i];
    }
    for(int i{0}; i>value[i];
    }
    std::vector> dp(m, std::vector(n+1, 0));
    for(int i{0}; i<=n; i++){
        dp[0][i] = i>=weight[0]?value[0]:0;
    }
    for(int i{1}; i

01背包问题 一维

链接

  1. 01背包问题可以用一维数组处理,但是需要注意遍历背包的顺序,应该从大到小遍历,因为遍历判断是否应该放入当前物品时,需要比较当前物品放入后剩余空间的最大价值,此时如果当前背包容量大于当前物品空间的两倍,则正序遍历时会将其放入两次,例:dp[j] = max(dp[j], dp[j-weight[i]+value[i]),若当前背包容量为5,物品重量为2,物品价值特别大,则比较未放入当前物品时的价值背包容量为3时的价值与当前物品价值的和,这里假如是从小到大遍历,则在判断容量为3时,因为当前物品价值特别大,已经放入,会与当前再次放入矛盾,导致错误,所以应该从大到小遍历,确保比较时当前物品没有被放入比较过
#include 
#include 

int main(){
    int m, n;
    std::cin>>m>>n;
    std::vector weight(m,0),value(m,0);
    for(int i{0}; i>weight[i];
    }
    for(int i{0}; i>value[i];
    }
    //
    std::vector dp(n+1,0);
    for(int i{0}; i=weight[i]; j--){
            dp[j] = std::max(dp[j], dp[j-weight[i]]+value[i]);
        }
    }
    std::cout<

416. 分割等和子集

  1. 本质上也是01背包问题,相当于每个数字是一个物品,价值和体积都等于数字本身,有一个总和一半大小的背包,要求背包放入物品的价值总和尽量最大,最大是sum/2,如果能达到sum/2,说明可以划分为两个相同大小的子集
class Solution {
public:
    bool canPartition(vector& nums) {
        int sum{0};
        for(const auto& val:nums){
            sum += val;
        }
        if(sum%2!=0){
            return false;
        }
        //
        std::vector dp(sum/2+1,0);
        for(int i{0}; i=nums[i]; j--){
                dp[j] = std::max(dp[j], dp[j-nums[i]]+nums[i]);
            }
        }
        return dp[sum/2]==sum/2;
    }
};

你可能感兴趣的:(算法)