对于01背包,用二维数组做DP的情况如下:
F[i,v]代表,在背包容量为v的情况下,从前i件物品中选出若干件(因背包容量的限制,可能不会所有i件都在里面,取最大值时背包里应该是权值相对较大的那些物品)所能得到的最大价值。
第一句对dp设置初始条件。
两个for循环遍历所有的情况:i从1~N表示从i件物品中选取,v从ci~V表示背包的大小(现在考虑的是第i件物品的放与不放,因此背包应该至少大于等于i物品的费用,否则无意义)
最关键的问题在于max{F[i-1,v],F[i-1,v-Ci]+wi}这一句
F[i-1,v]表示在背包容量v的情况下,从前i-1个物品中怎样放置使价值最大,这也代表,对于第i件物品,我们不选择将它放入背包,而去从前i-1个物品中选择放置策略,但这与F[i-1,v-Ci]是不同的,因为我们现在只是选择不把这个i放进去,而不代表我们要削减背包的容量。
F[i-1,v-Ci]+wi表示,在背包容量为v的情况下,我们选择将这个第i件物品放入背包的情况。此时F[i,v]应该是,在放入之前背包的最大价值,加上放入之后的最大价值。而放入之前背包的最大价值为F[i-1,v-Ci]。
仔细思考F[i-1,v]与F[i-1,v-Ci]的区别:
现在我们计算的是F[i,v],也就是说背包的容量已经定死为v了,F[i-1,v]是因为我们放弃了将i加入背包,背包的容量是不变的。而F[i-1,v-Ci]是因为,现在我们选择将i加入背包,也就是说,这个背包至少已经有一个i了,这个i的容量也为Ci了,而背包总共为v,现在要计算它的最大价值,就要加上在v-Ci中,在前i-1个物品中做选择使背包容量最大的值了。
这个方法使用的是二维数组,而实际上,i时刻的结果只与i-1时刻下的策略有关。
我们考虑用一个一维数组来进行dp。
对于一维数组来说,它无法保存两个状态i与v,但是,由于i只与i-1有关,因此如果我们逐步更新i,在i时刻进行放置之前,F[v]实际上保存的就是i-1下的最优值,而更新后直到i+1时刻的放置策略之前,F[v]都保存的是i下的最优值。
因此:
首先解释下max{F[v],F[v-Ci]+Wi}:
我们已经明确了,F[v]表示的是i下的最优值。
而在i下,在进行到F[v]=max{F[v],F[v-Ci]+Wi};之前,我们看F[v],这个时候的F[v]实际上是保存的是i-1下背包容量为v的最优值,因此:
在对F[v]赋值之前,F[v]表示,不考虑第i件物品,只考虑前i-1个物品的情况下,在背包容量为v下的最优解。
而F[v-Ci]表示,在i-1下,背包容量为v-Ci的最优解,再加上右边的Wi,就表示一定将i放入背包的情况。
在解释下关于逆序的问题:
从上面可以看到,对v来说,它是从V递减到Ci的,而且一定只能是逆序,这是因为:
从内循环来说,每一次内循环,都相当于更新在i下,背包容量为v最优解。更新之前,F[v]表示i-1下的最优解,而一旦赋值结束,F[v]就表示i下的最优解了。
如果为顺序,当我们进行到F[v]时,要使用到F[v-Ci],但是这个F[v-Ci]必须是i-1下的最优解,而由于顺序的原因,在我们将v递增到(顺序的情况下)v时,已经经历了v-Ci这个背包容量了,换句话说,此时v下的F[v-Ci],已经代表的是i下背包容量为v-Ci的最优解了,而我们需要的是i-1下,背包容量为v-Ci的最优解!
因此,我们必须要使用逆序,这样当进行到v时,F[v-Ci]还未更新,它还依然表示i-1下的最优解。