有 N件物品和一个容量为 V 的背包,每件物品有各自的价值且只能被选择一次,要求在有限的背包容量下,装入的物品总价值最大。「0-1 背包」是较为简单的动态规划问题,也是其余背包问题的基础。
动态规划是不断决策求最优解的过程,「0-1 背包」即是不断对第 i个物品的做出决策,「0-1」正好代表不选与选两种决定。
二维代码实现
#include<iostream>
using namespace std;
const int N=1e3+10;
int v[N],w[N],f[N][N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j]; //当前背包容量j<v[i],所以前i个物品最大值与前i-1个相同
if(j>=v[i]) //如果j>v[i],进行选择放与不放第i个物品
f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[n][m]<<endl;
return 0;
}
一维代码
#include<iostream>
using namespace std;
const int N=1e3+10;
int v[N],w[N],f[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
for(int i=1;i<=n;i++){
for(int j=m;j>=a[i];j--){
f[j]=max(f[j],f[j-v[i]]+w[i]); //背包容量是从大到小的因此j一定大于a[i]
}
}
cout<<f[m]<<endl;
return 0;
}
for(int j=m;j>=a[i];j--){
f[j]=max(f[j],f[j-v[i]]+w[i]); //背包容量是从大到小的因此j一定大于a[i]
}
一定要从m开始进行逆序计算,在二维情况下f[i][j]是由i-1的状态得来的,f[i][j]与f[i-1][j]是完全独立的,但是当我们优化到一维后我们可能会在该使用i-1的位置用到i,例如,一维状态第i轮对体积为 3的物品进行决策,则f[7]由f[4]更新而来,这里的f[4]正确应该是f[i - 1][4],但从小到大枚举j这里的f[4]在第i轮计算却变成了f[i][4]。当逆序枚举背包容量j时,我们求f[7]同样由f[4]更新,但由于是逆序,这里的f[4]还没有在第i轮计算,所以此时实际计算的f[4]仍然是f[i - 1][4]