Unverified Commit f0938efd authored by Xeonacid's avatar Xeonacid Committed by GitHub
Browse files

Update knapsack.md

parent e50f6218
Loading
Loading
Loading
Loading
+23 −20
Original line number Diff line number Diff line
@@ -22,9 +22,11 @@ f_{i,j}=\max(f_{i-1,j},f_{i-1,j-w_{i}}+v_{i})
$$

在程序实现的时候,由于对当前状态有影响的只有 $f_{i-1}$,故可以去掉第一维,直接用 $f_{i}$ 来表示处理到当前物品时背包容量为 $i$ 的最大价值,得出以下方程:

$$
f_i=max \left(f_i,f_{i-w_i}+v_i\right)
f_i=\max \left(f_i,f_{i-w_i}+v_i\right)
$$

**务必牢记并理解这个转移方程,因为大部分背包问题的转移方程都是在此基础上推导出来的。**

还有一点需要注意的是,很容易写出这样的错误核心代码:
@@ -233,8 +235,7 @@ for (int k=1;k<=ts;k++)//循环每一组

这种背包问题其实就是如果选第$i$件物品,就必须选第 $j$ 件物品,保证不会循环引用,一部分题目甚至会出现多叉树的引用形式。为了方便,就称不依赖于别的物品的物品称为“主件”,依赖于某主件的物品称为“附件”。

对于包含一个主件和若干个附件的集合有以下可能性:仅选择主件,选择主件后再选择一个附件,选择主件后再选
择两个附件……需要将以上可能性的容量和价值转换成一件件物品。因为这几种可能性只能选一种,所以可以将这看成分组背包。
对于包含一个主件和若干个附件的集合有以下可能性:仅选择主件,选择主件后再选择一个附件,选择主件后再选择两个附件……需要将以上可能性的容量和价值转换成一件件物品。因为这几种可能性只能选一种,所以可以将这看成分组背包。

如果是多叉树的集合,则要先算子节点的集合,最后算父节点的集合。

@@ -275,12 +276,14 @@ for (从最后一件循环至第一件)//因为最后一件物品存储的是最
这种问题就是把求最大值换成求和即可。

例如 0-1 背包问题的转移方程就变成了:

$$
dp_i=sum(dp_i,dp_{i-c_i})
dp_i=\sum(dp_i,dp_{i-c_i})
$$

初始条件:$dp_0=1$

因为当容量为0时也有一个方案:什么都不装!
因为当容量为 $0$ 时也有一个方案:什么都不装!

#### 求最优方案总数