一、题目打卡
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;
}
};
做的磕磕绊绊的,主要是这个题的价值和重量是同一个东西,让我一时没反映过来。