这里先说一下二维的。
///01背包
///设物品有n件物品,背包容量为w
int w[]; ///代表n件物品的价值
int pw[]; ///代表n件物品各占的容量
int f[n+50][w+50]; ///最优解二维数组
///f[i][j]数组 代表存i件物品在容量为j的背包中得到的价值
void package_01(){
for(int i=0;i<=n;i++) f[i][0]=0;
for(int j=0;j<=c;j++) f[0][j]=0; ///初始化, ///若要求恰好装满,除这两个初始化外,其他值全部赋值为 -0x3f3f3f3f,(这样能够保证最后恰好装满)
///
for(int i=1;i<=n;i++){ ///有点枚举的感觉,枚举n件物品
for(int j=pw[i];j<=c;j++){ ///与上同理
if(f[i-1][j-pw[i]]+w[i]>f[i-1][j]) ///i-1件物品放入j-pw[i]容量的价值+w[i]的价值(即为放) 与 i-1件物品放入j容量(即为不放) 的所得价值比较
f[i][j]=f[i-1][j-pw[i]]+w[i];
else f[i][j]=f[i-1][j];
}
}
printf("%d\n",f[n][w]); ///f[n][w]即为最优解
}
二维的状态转移方程
很显然,f[i][*] 只与 f[j-1][*] 的状态有关 所以这里可以有空间上的优化。
先看代码:
memset(dp, 0, sizeof(dp));
for(int i=0; i<n; i++){
for(int j=c; j>=pw[i]; j--){
dp[j] = max(dp[j], dp[j-pw[i]]+w[i])
}
}
对于外层的循环,每进行一次,dp[] 保存的状态都还是 i - 1 时候的dp[] ,所以在第二层循环使用的时候就相当于使用的是
dp[i - 1][j - pw[i]] + w[i] 与 dp[i-1][j] ..
并且,状态转移方程,每一次推导 f[i][j] 是通过 f[i-1][j-w[i]] 来推导的,所以一维数组中j的扫描顺序应该从大到小(c 到 0),否者前一次循环保存下来的值将会被修改,从而造成错误。