背包DP

背包DP

0-1背包

问题:有 nn 个物品和一个容量为 WW 的背包,每个物品有重量 wiw_i 和价值 viv_i 两种属性,要求选若干物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。

每个物品只有取和不取两种选择,所以称为0-1背包问题。

设DP状态fi,jf_{i,j}为只放前ii个物品的情况下,容量为jj的背包可以达到的最大价值。则有:

fi,j=max(fi1,j,fi1,jwi+vi)f_{i,j} = \max(f_{i-1,j}, f_{i-1,j-w_i}+v_i)

这样的话状态是一个二维数组,直接的一个优化是观察到fi,...f_{i,...}只和fi1,...f_{i-1,...}有关系,所以可以去掉ii这一维,直接在fjf_j上面做状态的更新,也就是:

fj=max(fj,fjwi+vi)f_j = \max(f_j,f_{j-w_i}+v_i)

这样就把状态简化成了一维,节省了大量内存。要注意的是,因为fjf_j依赖fk(kj)f_k (k \leq j),所以更新fjf_j的时候,需要从大到小更新,才能不覆盖后面需要使用到的值。

模板代码:

for (int i = 1; i <= n; i++)
  for (int l = W; l >= w[i]; l--) 
    f[l] = max(f[l], f[l - w[i]] + v[i]);

更多背包

关于完全背包、多重背包、混合背包等,请参照OI-Wiki

习题

习题
T200147通天之分组背包普及-
T204510越越的组队普及-
T204512榨取kkksc03普及-
T200143深基12.例1部分背包问题普及/提高-
T200145USACO集合 Subset Sums普及/提高-
T191609NOIP-S金明的预算方案2006普及+/提高
T191608SNOI英雄联盟2017普及+/提高
CF543ACFWriting Code普及+/提高
T191967NOIP-S飞扬的小鸟2014普及+/提高
CF1381BCFUnmerge普及+/提高
T205905不开心的金明普及+/提高
CF577BCFModulo Sum提高+/省选-
T205880HNOI产品加工2001提高+/省选-