一、01背包
(1)dp数组定义:当目前背包容量为j时,从第0件物品遍历到第i件物品的最大价值
(2)递推公式:dp[i][j]=dp[i-1][j](一定装不下第i件物品,即j<weight[i]时)
dp[i][j]=dp[i-1][j](能装下,但是不装这件时)
value[i]+dp[i-1][j-weight[i]](能装下,同时也要装下这件)
因为本题的遍历j是从0开始遍历,临界点是j为第i件物品的质量,所以能装下的情况可能是要把之前装的所有的物品都拿出去,再放第i件,因此第i件单件的价值可能不如之前小件加起来都和。所以在能装下的情况里边又包含了两种情况进行比较,取最大值的操作。
(3)初始化:在建立数组的时候,默认全为0,因此第一列不用管,其含义是当背包容量为0时,所有的物品都装不下,因此价值也都为0。第一行要从j=weight[0]时开始,第一行第j列以后全都赋值成value[0],其含义是在等于weight[0]之前,背包放不下,默认价值为0,等到可以放下以后,(同时第一行的意思是只放第0件物品)后面全都赋值为第0件物品的价值。
(4)遍历顺序:在物品内遍历容量
(5)返回右下角的元素
#include<iostream>
#include<vector>
using namespace std;
int m,bagweight;
void solve(){
vector<int>weight(m,0);
vector<int>value(m,0);
for(int i=0;i<weight.size();i++){
cin>>weight[i];
}
for(int j=0;j<value.size();j++){
cin>>value[j];
}
vector<vector<int>>dp(m,vector<int>(bagweight+1,0));
//初始化
for(int i=weight[0];i<=bagweight;i++){
dp[0][i]=value[0];
}
for(int i=1;i<m;i++){
for(int j=0;j<=bagweight;j++){
if(j<weight[i])dp[i][j]=dp[i-1][j];
else{
dp[i][j]=max(dp[i-1][j],value[i]+dp[i-1][j-weight[i]]);
}
}
}
cout<<dp[m-1][bagweight];
}
int main(){
while(cin>>m>>bagweight){
solve();
}
return 0;
}
注意这里的m是物品的种类数,而i是第i件,前者从1开始计数,后者从0开始计数,这里的开闭要注意。
二、回滚数组,一维数组实现01背包
和二维数组的区别是:
这里需要倒序遍历背包容量,以此来保证每件物品只取一次。
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
int main(){
int m,bagspace;
cin>>m>>bagspace;
vector<int>weight(m+1,0);
vector<int>value(m+1,0);
vector<int>dp(bagspace+1,0);
for(int i=1;i<weight.size();i++){
cin>>weight[i];
}
for(int j=1;j<value.size();j++){
cin>>value[j];
}
for(int i=1;i<=m;i++){
for(int j=bagspace;j>0;j--){
if(j<weight[i])dp[j]=dp[j];
else dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
cout<<dp[bagspace];
return 0;
}
三、切割等和子集
这题很难想到的点是如何把它转化成背包问题,即让价值等于重量 。不过我理解的是,判断在背包可以被装满(j==target)的时候,此时是否被装满 ,不引入价值这个概念。
需要注意的是,求和之后先判断它是否为奇数,若为奇数则直接返回不成立。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum=0;
for(int i=0;i<nums.size();i++){
sum+=nums[i];
}
if(sum%2!=0)return false;
int target=sum/2;
vector<int>dp(target+1,0);
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]);
}
}
if(dp[target]==target)return true;
return false;
}
};