AC代码:
#include <iostream>
#include <math.h>
#include <string>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> m >> n;
// dp[i][j]:大小为i的背包存放0-j的材料,最大价值是多少
vector<vector<int>> dp(n + 1, vector<int>(m, 0));
vector<int> weight(m);
vector<int> value(m);
for (int i = 0; i < m; ++i) {
cin >> weight[i];
}
for (int i = 0; i < m; ++i) {
cin >> value[i];
}
// 放下标为0的物品
for (int i = weight[0]; i <= n; ++i) {
dp[i][0] = value[0];
}
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < m; ++j) {
// 当weight[j]大于当前背包容量,只能不放物品j,
// 因此背包容量为i时要放0-j的物品的价值就等于0-j-1的价值
if (weight[j] > i) {
dp[i][j] = dp[i][j - 1];
} else {
// 放下标为j的物品,或是不放,取最大值
dp[i][j] = max(dp[i][j - 1], dp[i - weight[j]][j - 1] + value[j]);
}
}
}
cout << dp[n][m - 1] << endl;
return 0;
}
滚动数组版本 注意:要先遍历物品,后遍历背包,这样,每个容量的背包才会计算一次物品j是否要存放进来;否则先遍历背包,后遍历物品,相当于每个容量的背包只会在所有物品中选一个存放 另外,容量要从大到小遍历,因为计算大小为i的背包放物品j的价值需要大小为i-1的背包不放物品j的价值,如果容量从小到大,那么前面的i-1大小的结果会先被覆盖掉
#include <iostream>
#include <math.h>
#include <string>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> m >> n;
// dp[i][j]:大小为i的背包存放0-j的材料,最大价值是多少
// vector<vector<int>> dp(n + 1, vector<int>(m, 0));
vector<int> dp(n + 1);
vector<int> weight(m);
vector<int> value(m);
for (int i = 0; i < m; ++i) {
cin >> weight[i];
}
for (int i = 0; i < m; ++i) {
cin >> value[i];
}
for (int j = 0; j < m; ++j) {
for (int i = n; i >= weight[j]; --i) {
// 放下标为j的物品,或是不放,取最大值
dp[i] = max(dp[i], dp[i - weight[j]] + value[j]);
}
}
cout << dp[n] << endl;
return 0;
}
代码如下:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2 == 1)
return false;
int half = sum / 2;
// 0-i的数是否能构成大小为j的总和
vector<bool> dp(half + 1);
dp[0] = true;
for (int i = 0; i < nums.size(); ++i) {
for (int j = half; j >= nums[i]; --j) {
// 要么,延续之前的结果
// 要么,看当前容量j加进来nums[i]之前,
// 也就是0-(i-1)的数是不是能满足j - nums[i]
dp[j] = dp[j] || dp[j - nums[i]];
}
}
return dp[half];
}
};
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
// dp[i]中的i表示背包内总和
// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
vector<int> dp(10001, 0);
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
// 也可以使用库函数一步求和
// int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2 == 1) return false;
int target = sum / 2;
// 开始 01背包
for(int i = 0; i < nums.size(); i++) {
for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
// 集合中的元素正好可以凑成总和target
if (dp[target] == target) return true;
return false;
}
};