背包九讲

考前两天,再看一下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])

posted @ 2018-11-08 14:47  Ilverene  阅读(315)  评论(0编辑  收藏  举报