目录
01背包
二维数组
注意:
- 初始化
- 遍历顺序
//二维dp数组实现
#include <bits/stdc++.h>
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];
}
// dp数组, dp[i][j]代表行李箱空间为j的情况下,从下标为[0, i]的物品里面任意取,能达到的最大价值
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
// 初始化, 因为需要用到dp[i - 1]的值
// j < weight[0]已在上方被初始化为0
// j >= weight[0]的值就初始化为value[0]
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
for(int i = 1; i < weight.size(); i++) { // 遍历科研物品
for(int j = 0; j <= bagweight; j++) { // 遍历行李箱容量
// 如果装不下这个物品,那么就继承dp[i - 1][j]的值
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
// 如果能装下,就将值更新为 不装这个物品的最大值 和 装这个物品的最大值 中的 最大值
// 装这个物品的最大值由容量为j - weight[i]的包任意放入序号为[0, i - 1]的最大值 + 该物品的价值构成
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[weight.size() - 1][bagweight] << endl;
}
int main() {
while(cin >> n >> bagweight) {
solve();
}
return 0;
}
滚动数组
从后向前遍历,不能让上一个状态影响到当前状态
void test_1_wei_bag_problem() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagWeight = 4;
// 初始化
vector<int> dp(bagWeight + 1, 0);
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[bagWeight] << endl;
}
int main() {
test_1_wei_bag_problem();
}
416分割等和子集
如何转化当前问题为01背包呢?
我们设计一个背包,能存储的最大数量为nums的sum的一半,如果能存满,就说明能分割出一个等和的子集
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;i++)
{
sum+=nums[i];
}
if(sum%2==1)
{
return false;
}
int bag=sum/2;
vector<int> dp(bag+1,0);
for(int i=0;i<n;i++)
{
for(int j=bag;j>=nums[i];j--)
{
dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
if(dp[bag]==bag)
{
return true;
}
return false;
}
};
1049最后一块石头的重量
和上一题类似,求出石头一半重量的最大值,再用sum-2*最大值,得到的结果就是剩下的石头的重量
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int n=stones.size();
int sum=0;
for(int i=0;i<n;i++)
{
sum+=stones[i];
}
int bag=sum/2;
vector<int> dp(bag+1,0);
for(int i=0;i<n;i++)
{
for(int j=bag;j>=stones[i];j--)
{
dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);
}
}
return sum-dp[bag]*2;
}
};
494目标和
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
/*如何转换问题为dp?
nums有一个总和,就拿用例来讲:
sum=5,target=3,
也就是我们需要找到凑出1的不同方法
sum-2*1=3
dp数组含义:填满空间为j的背包,有dp[j]种方法
递推思路:凑整dp[5]有多少方法呢,假设当前dp[3]已知,nums[i]==2
那么当前dp[5]中必然有dp[3]=dp[5-nums[i]]
也就是把 所有的 dp[j - nums[i]] 累加起来
递推公式:dp[j]=dp[j]+dp[j-nums[i]]
初始化:dp[0]=1
*/
int sum=0;
int n=nums.size();
for(int i=0;i<n;i++)
{
sum+=nums[i];
}
int find2=sum-target;
if(find2%2==1||find2<0)
{
return 0;
}
int findval=find2/2;
vector<int> dp(findval+1,0);
dp[0]=1;
for(int i=0;i<n;i++)
{
for(int j=findval;j>=nums[i];j--)
{
dp[j]=dp[j]+dp[j-nums[i]];
}
}
return dp[findval];
}
};
标签:weight,nums,int,sum,vector,动态,规划,dp
From: https://www.cnblogs.com/liviayu/p/17969757