算法学习 | day36/60 背包问题/分割等和子集

文章讲述了二维背包问题的解题过程,通过C++代码展示了如何运用动态规划方法求解,并讨论了滚动数组的实现方式。同时提及了子集划分问题,强调了在价值和重量相同时的思考难点。
摘要由CSDN通过智能技术生成

一、题目打卡

        1.1 二维背包问题

        题目链接:46. 携带研究材料(第六期模拟笔试)

#include<iostream>
#include<vector>
using namespace std;


int n, bagweight;// bagweight代表行李箱空间
void solve() {
    vector<int> weight(n, 0); // 存储每件物品所占空间
    vector<int> value(n, 0);  // 存储每件物品价值
    for(int i = 0; i < n; ++i) {
        cin >> weight[i];
    }

    for(int j = 0; j < n; ++j) {
        cin >> value[j];
    }
    // 一开始就初始化为0,第一列就不用考虑了
    vector<vector<int>> dp(n,vector<int>(bagweight + 1,0));
    
    // 第一行的初始化要从满足重量要求的位置开始初始化
    for(int i = weight[0]; i <= bagweight;i++){
        dp[0][i] = value[0];
    }
    
    for(int i = 1; i < n;i++){
        for(int j = 1 ; j <= bagweight;j++){
            if(weight[i] > j){
                dp[i][j] = dp[i-1][j]; // 超重了就继承上方
                continue;
            }
            // 不选择i
            dp[i][j] = max(dp[i][j],dp[i-1][j]); // 来自上方
            //选择i
            dp[i][j] = max(dp[i][j],dp[i-1][j - weight[i]] + value[i]);
        }
    }
    // for(auto &i:dp){
    //     for(auto &j:i){
    //         cout << j << " ";
    //     }
    //     cout << endl;
    // }
    
    cout << dp[n - 1][bagweight];
}

int main() {
    while(cin >> n >> bagweight) {
        solve();
    }
    return 0;
}

       

         先看了视频再做的,思路相对清楚了很多,我感觉这个题目递归的过程不是很复杂,反而不好理解的是这个状态的定义,还有就是写的过程中,这个索引用着的感觉也有点奇怪,但是我说不清楚,还是写一个案例自己分析一下比较好,然后就是注意一下,本身在递推的过程中,我忽略的一个情况,就是当前的物品重量肯定放不进的情况,还有就是dp[i-1][j-weight],这个地方的j,我写成的bagWeight,这样就没有递推的过程了。

        然后是滚动数组的写法,这样确实和二维数组有很多不一样的地方:

// 滚动数组
void solve_with_scrolling_array(){
    // 这里 dp 数组的定义就改变了,这里的dp[i]代表的是背包容量为i的时候,用所有的资源能装下的最大的价值
    vector<int> dp(bagweight+1,0), weight(n,0), value(n,0);
    for(int i = 0; i < n;i++){
        cin >> weight[i];
    }
    
    for(int i = 0; i < n;i++){
        cin >> value[i];
    }
    // for(int i = weight[0];i<bagweight;i++){
    //     dp[i] = value[0];
    // }
    
    for(int i = 0 ; i < n;i++){ // 这里的循环代表的是选择的种类索引
        for(int j = bagweight; j >= weight[i];j--){
            // if(weight[i] > j) continue;
            dp[j] = max(dp[j],dp[j-weight[i]] + value[i]); //dp[j]其实就表示的是这个值不发生变化,也就是不选择
        }
    }
    cout << dp[bagweight];
}

        首先是这个不能用第一个物品进行初始化,因为这样就是默认第一个物品加进去了,这样用后面倒序的方法的时候,会计算重复,之所以要用倒序,是因为一维数组无法存储左上和上的数据,这样使用当前层,就会导致当前的物品被计算了多次,所以要从后向前进行计算。特别的是这个终止的条件,其实就是之前二维数组 if 中需要继承上一个数值的一个处理。

        1.2 分割等和子集

        题目链接:. - 力扣(LeetCode)

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(auto& it: nums){
            sum += it;
        }
        if(sum % 2 != 0) return false; // 这种不可能分割成

        int n = nums.size(), bagweight = sum/2;
        vector<int> dp(bagweight + 1,0);

        for(int i = 0; i < n;i++){ // 相当于遍历每个物品
            for(int j = bagweight; j >= nums[i];j--){
                dp[j] = max(dp[j],dp[j - nums[i]] + nums[i]);
            }
        }
        if(dp[bagweight] == sum/2) return true;
        return false;


        // sort(nums.begin(),nums.end());
        // int tmp = 0;
        // int i = 0;
        // for(; i < nums.size();i++){
        //     tmp += nums[i];
        //     if(tmp == sum/2) break;
        // }
        // ++i;
        // int tmp1 = 0;
        // for(;i<nums.size();i++){
        //     tmp1 += nums[i];
        // }
        // return tmp1 == tmp;

    }
};

        做的磕磕绊绊的,主要是这个题的价值和重量是同一个东西,让我一时没反映过来。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值