01背包的标准写法是这样的,注意下标从0开始,防止越界:
for(int i=1;i<=m;i++){
for(int j=0;j<=n;j++){
e[i][j] = e[i-1][j];
if(j >= a[i]) e[i][j] = max(e[i][j], e[i-1][j-a[i]] + b[i]);
}
}
你的代码里j从1开始容易出错,而且if条件是j-a[i]<0而不是j>=a[i],而且数组e没初始化为0,导致垃圾值。输出时i和j也从0开始才对。
从网友分享:看了你的代码,问题在for(int j=1;j<=n;j++)这里,应该从j=0开始,因为j=0时也要不选物品,e[i][0]=0。另外if(j-a[i]<0)这个判断不对,应该是if(j>=a[i]),因为a[i]可能是0体积但有价值的情况,虽然01背包一般a[i]>0。并且e数组要memset(e,0,sizeof(e));初始化!
另一个帖子:01背包dp核心是dp[i][j]表示前i个物品容量j的最大价值。递推:dp[i][j] = max( dp[i-1][j] , dp[i-1][j - w[i]] + v[i] ) if j>=w[i] else dp[i-1][j]。容易出错的地方:1.数组下标,物品从1到m,容量从0到n。2.没初始化dp全为0。3.内层循环j从大到小如果是1维优化。你的二维没问题但循环j从1错,j=0必须是0。
知乎回答原文:动态规划解决01背包问题,前i物品放进容量为j的背包的最大价值。状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]+v[i]}。容易出错:1.初始化,f[0][0..V]=0,f[0..N][0]=0。2.循环顺序,外层物品1到N,内层体积0到V。3.判断体积是否够if(v>=w[i])。代码里用prev和curr两层节省空间也行。
博客摘录:用户代码问题总结:cin>>n>>m; n是容量m是物品数对,但a[1..m] b[1..m],e[101][101]如果n>100 m>100爆。for j=1 to n错,j=0要处理。if(j-a[i]<0)逻辑反了,应if(j>=a[i])。输出for i=0 to m, j=0 to n,对,答案e[m][n]。
论坛经验:01背包常错1.二维dp没清零,用vector
常见坑:数组大小,n m到1e5要1维反向。你的e[101][101]小数据ok但j从1漏j=0,e[i][0]应始终0。输出全表调试好,但正式只需cout<<e[m][n];你的输出i=0到m j=0到n对,能看到e[m][n]。
FAQ
Q: 为什么内层循环j要从0开始?
A: j=0表示容量0,只能不选任何物品,价值0,不从1开始会错。
Q: if(j-a[i]<0)为什么错?
A: 应写if(j>=a[i])才选,否则逻辑颠倒,选了不够容量的物品。
Q: 数组怎么初始化?
A: 用memset(e,0,sizeof(e));或vector全0构造,否则垃圾值导致max错。
Q: 二维dp空间不够怎么优化?
A: 用一维dp,从后往前更新,避免覆盖前一层数据。