1.分类
- 01背包:每件物品只能取一次,在容量有限的情况下使得权重最大
- 完全背包:与01背包问题不同的是,每种物品可以取无限次
- 多重背包:每种物品可以取有限个
- 分组背包:有N组,每一组只能选一个
2. 01背包问题
2.1解题步骤
2.1.1 状态表示
考虑用几维状态表示:f[i][j]
- 集合:所有选法的集合,满足两个条件,只从前i个物品选,选出来的物品总体积小于等于j
- 属性:(最大值,最小值,数量),本题中是最大值
注:若要对dp问题进行优化,一般是对状态方程进行等价变形
2.1.2 状态计算
集合的划分,本题中状态可以划分为两个部分
- 所有包含第i个物品的方案:f(i-1,j-weight[i])+value[i]
- 所有不包含第i个物品的方案:f(i-1,j)
然后对两种情况取max
2.1.3 AC代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int value[N];
int weight[N];
int n,v;
int f[N][N];
int main(){
cin>>n>>v;
int a,b;
for(int i=1;i<=n;i++){
cin>>a>>b;
weight[i]=a;
value[i]=b;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=v;j++){
f[i][j]=f[i-1][j];
if(j>=weight[i]){
f[i][j]=max(f[i][j],f[i-1][j-weight[i]]+value[i]);
}
}
}
cout<<f[n][v];
return 0;
}
2.1.4 优化代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int value[N];
int weight[N];
int n,v;
int f[N];
int main(){
cin>>n>>v;
int a,b;
for(int i=1;i<=n;i++){
cin>>a>>b;
weight[i]=a;
value[i]=b;
}
for(int i=1;i<=n;i++){
for(int j=v;j>=weight[i];j--){
if(j>=weight[i]){
f[j]=max(f[j],f[j-weight[i]]+value[i]);
}
}
}
cout<<f[v];
return 0;
}
可以将二维数组编程一维数组,因为可以看到在状态转移方程的更新中,第i层都是用的i-1层的数据在进行更新,这种情况下只需要一维就可以解决了。另外一个重要的点就是,可以看到j这一维每次都是用的小于j的数据在更新,所以j的枚举应该从大到小枚举,否则就会发生用第i层数据更新i层数据的情况。