一、题目
二、题解
2.0_思路
将石头分成总和相近的两堆时,碰撞后剩余的石头为最小
求得所有石头总重量int sum=accumulate(stones.begin(),stones.end(),0)
dp数组放当前放入的最大重量
取target=sum/2(先不管sum奇偶)
问题转为背包容量为target,求能够放入的最大重量
最后返回target-dp[target]即可
2.1_动态规划
2.1.1_确认dp数组含义
先写写出二维dp数组
dp[i][v]:有i个物品,背包容量为v时,背包能够装入的最大容量
对应的一维dp数组就是将二维的中的i维度转为for循环
dp数组改为dp[v]
2.1.2_写出递推公式
要得到最大的装入量
那就应该
当前背包容量减去当前物品体积的情况若是能够装满
则当前背包就可以装满
dp[v]=max(dp[v],dp[v-stones[i] ]+stones[i] )
2.1.3_初始化
1^最后需要用到dp[target]进行运算,所以dp数组要多开一位
2^初始状态为没有物品可以选择时各个背包容量下能够放入的最大重量
所以全部初始化为0
vector<int> dp(target+1,0);
2.1.4_deBug&完整代码
deBug:
1^最开始我获取背包容量直接这样写
int target=(accumulate(stones.begin(),stones.end(),0))/2;
......
// 返回答案
return target-dp[target];
这样会导致一个问题:
当石头重量总和为奇数时,我未记录原始数据,而是直接令target对求和取半
因为target是整形变量,target后面的小数会被舍去
返回答案时我用变小的target-dp[target],答案也就少了1
应该改成:
int sum=accumulate(stones.begin(),stones.end(),0);
int target=sum/2;
......
// (sum-dp[target])表示另一堆石头的总重量
return (sum-dp[target])-dp[target];
完整代码:
#include<iostream>
#include<vector>
#include<numeric>
using namespace std;
int lastStoneWeightII(vector<int>& stones) {
// 获取背包容量
int sum = accumulate(stones.begin(), stones.end(), 0);
int target = sum / 2;
// 定义dp数组并初始化为0
vector<int> dp(target + 1, 0); // 要取索引为target的值进行比较,大小就要多开1
// 由递推公式遍历dp数组
for (int stone_i : stones)
for (int v = target; v >= stone_i; v--)
dp[v] = max(dp[v], dp[v - stone_i] + stone_i);
// 返回最后的差值
return sum - dp[target] - dp[target];
}
总结
这类题难在了如何转到背包问题上进行求解