动态规划
DP:状态表示和状态计算(状态子集的划分)
状态标识:集合(只考虑前i个物品,且体积不大于j的选法)、属性
01背包问题
c++
二维
1 |
|
一维
1 |
完全背包
思路
曲线救国:1.去掉k个物品i
2.求max,
将集合划分为,包含第i个,不包含第i个
前者:\(f[i][j]\)
后者:\(f[i-1][j-kv[i]]+kw[i]\)
初步代码
1 |
|
优化
对状态计算进行优化
对于 \[ \begin{aligned} f[i][j]=max(f[i-1][j],&f[i-1][j-v]+w,f[i-1][j-2v]+2w,\ldots)\\ f[i][j-v]=max(&f[i-1][j-v],f[i-1][j-2v],\ldots) \end{aligned} \] 因此 \[ f[i][j]=max(f[i-1][j],f[i][j-v]+w) \]
1 |
|
完全背包和01背包比较
多重背包
加入 k<=s[i]的额外条件即可,其他与多重背包完全一致
初步代码
1 |
|
优化
二进制离散优化
将每个具有 \(s\) 个的物品,分解成 \(\log_2 s\) 堆物品,例如1 ,2,4等等,这些必然可以组合0到s的任意数,因此这样的分解是和原问题等效的。
将 \(n\) 种物品全都分解
最后再使用01背包问题解法即可
1 |
|
组合背包
思路: 考虑多重背包的思想,仅仅将每个物品选几个替换成——选当前组的哪一个物品
初始代码
1 |
|
在更新状态时,需要考虑每个组内选择每个物品的情况,且在同一个背包容量下,应该是在上一个状态的基础上考虑新增物品的价值,而不是直接使用f[i][j] = f[i-1][j]
来更新。这一行在循环开始前只需设置一次,而不是在每次考虑新物品时都重置。
优化
1 |
|