背包九讲
考前两天,再看一下dd的背包九讲,巩固一下。(毕竟我DP实在是太弱了)
01背包
模型
有\(N\)个物品,每个费用为\(V_i\),价值为\(W_i\),总钱数为\(C\),求最大价值。
子状态
\(f[i][j]\)表示前\(i\)件总钱数为\(j\)情况下的最大价值。
朴素转移
朴素转移每一次讨论当前物品到底取不取。
状态转移方程为\(f[i][j]=min(f[i-1][j],f[i-1][j-w[i]]+v[i])\)
空间优化
由于每一层的取值只需要依赖上一层的值,因此在实现的时候可以省略第一维。
但是这个时候原第二位的遍历需要采取倒叙,这样就可以保证我们遍历到\(f[j]\)的时候\(f[j-w[i]]\)里面保存的是原来\(f[i-1][j-w[i]]\)的值。
伪码实现
FOR i from 0 to C
f[0][i]=0
FOR i from 1 to n
FOR j from Vi to C
f[i][j]=min(f[i-1][j],f[i-1][j-w[i]]+v[i])
FOR i from 0 to C
f[i]=0
FOR i from 1 to n
FOR j from C downto Vi
f[j]=min(f[j],f[j-w[i]]+v[i])
细节
如果题目不要求背包要恰好装满,那么照常初始化。
但如果要求背包恰好装满,那么\(f[1]\)到\(f[C]\)都必须设为\(-INF\)(因为只有\(f[0]\)是刚好装满),而最后的答案为\(f[C]\)。
完全背包
模型
有\(N\)种物品,每种都有无限个,其余同01背包。
子状态
考虑01背包的空间优化写法,我们发现,之所以不可以顺序写,是因为这样同样的一件物品可能会被取多次。
这恰好是完全背包问题所允许的。
因此完全背包问题采用顺序的写法。
子状态为\(f[i]\),表示容量为\(i\)的背包最多能放多少个。
转移
上面说了
代码实现
FOR i from 0 to C
f[i]=0
FOR i from 1 to n
FOR j from Vi to C
f[j]=min(f[j],f[j-w[i]]+v[i])