子集背包再进化--石子对撞问题

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了子集背包再进化--石子对撞问题相关的知识,希望对你有一定的参考价值。

题目

在这里插入图片描述

题目解析

在这里插入图片描述

个人手写的详解,感觉已经比较详细了,接下来就是根据这个思路写下dp函数,利用dp背包分堆得到背包种的最大值,这是很多题目的惯用伎俩。此处的sum/2实际上无论sum是偶数还是奇数都不影响它的小的那一堆(反正sum/2是向下取整)

解题代码

二维数组形式
在这里插入图片描述

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        //accumulate函数是C++中的内置求和函数,三个参数,首地址~末地址+加法初始值
        int sum = accumulate(stones.begin(),stones.end(),0);
        //创建存储sum/2向下取整容量的背包,用于计算这个容量下最多装入多重的石子
        //base case肯定是背包容量为0时是0,遍历方向不再过多强调了,可以自己想想二维数组(遍历方向的思考是压缩为一维的关键)
        int dp[stones.size()+1][sum/2+1];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=stones.size();i++){
            for(int j=1;j<=sum/2;j++){
                //装
                if(stones[i-1]<=j)
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-stones[i-1]]+stones[i-1]);
                //不装
                else
                    dp[i][j] = dp[i-1][j];
            }
        }
        //得出A(偏大的)-B的结果
        int B = dp[stones.size()][sum/2];
        int A = sum-dp[stones.size()][sum/2];
        return A-B;
    }
};

压缩一维

由于dp关系仅仅和上一行数据相关,而且需要保证一直是上一行的数据,所以倒序遍历,当然倒序由base case来看也是合法的顺序。
在这里插入图片描述

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        //accumulate函数是C++中的内置求和函数,三个参数,首地址~末地址+加法初始值
        int sum = accumulate(stones.begin(),stones.end(),0);
        int dp[sum/2+1];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=stones.size();i++){
            for(int j=sum/2;j>=1;j--){
                //装
                if(stones[i-1]<=j)
                    dp[j] = max(dp[j],dp[j-stones[i-1]]+stones[i-1]);
                //不装
                else
                    dp[j] = dp[j];
            }
        }
        //得出A(偏大的)-B的结果
        int B = dp[sum/2];
        int A = sum-dp[sum/2];
        return A-B;
    }
};

以上是关于子集背包再进化--石子对撞问题的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些01背包问题,你该了解这些 滚动数组 416. 分割等和子集

LeetCode 446. 等差数列划分 II - 子序列(动态规划)/ 416. 分割等和子集 (背包问题)/322. 零钱兑换(完全背包)

1.从左往右尝试模型(背包问题)

动态规划第六篇:01背包问题(分割等和子集 + 最后一块石头的重量 II)

动态规划第六篇:01背包问题(分割等和子集 + 最后一块石头的重量 II)

子集树