01背包问题的理解...
题目链接:22背包专题 [Cloned] - Virtual Judge (csgrandeur.cn)
一开始有几个问题导致没有很明白...现在基本上可以理解了
首先就是对于mjz[i][j](max价值)数组的理解。是对于前i个物品有j个空间时拿的最大价值是多少。
然后就是状态转移方程:mjz[i][j]=max(mjz[i-1][j],mjz[i-1][j-w[i]]+jz[i]);
这个一开始有一点小问题就是为什么要取最大值,因为在拿取第i个物品的时候就要腾出来第i个物品的空间,而在腾出来这些物品的时候可能会丢掉一些物品,然后就要判断是丢掉这些物品然后加上第i个物品价值大还是不带上第i个物品的价值大..
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int mjz[105][10005];
int w[105],jz[105];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>w[i]>>jz[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j<w[i]) mjz[i][j]=mjz[i-1][j];
else {
mjz[i][j]=max(mjz[i-1][j],mjz[i-1][j-w[i]]+jz[i]);
}
}
}
cout<<mjz[n][m];
}
然后就是对01背包的优化..
在动态转移的时候其实就只用到了两行一维数组,那么就可以变成一维数组,分为原来和更新后的大小。就是和原来自己比较和带上i个物品比较...
那么状态转移方程就是:mjz[j]=max(mjz[j-w[i]]+jz[i],mjz[j]);
在一维的情况下注意j循环要从后开始,因为如果要从前开始的那么就会修改原来mjz[j-w[i]]的值会导致不是上一个状态的价值,而如果从后开始往前判断,mjz[j-w[i]]就是原状态下的价值。
优化代码:
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int mjz[10005];
int w[105],jz[105];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>w[i]>>jz[i];
}
for(int i=1;i<=n;i++){
for(int j=m;j>=w[i];j--){
mjz[j]=max(mjz[j-w[i]]+jz[i],mjz[j]);
}
}
cout<<mjz[m];
}