背包知识理解和总结:
01背包: 每种物品仅有一件,可以选择放与不放。
完全背包: 每种物品无限件。
多重背包: 第i种物品最多有n[i]件可用。
分组背包: 选择本组的某一件,还是一件不选。
★01背包:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} ;//f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。
因为该状态f[i][v]只与上一状态有关,所以出现了简化(一维):
f[v]=max{f[v],f[v-c[i]]+w[i]}
还有,一点!逆序!
因为求容量v的状态值时,只与前i-1件物品装入容量小于或等于v的状态有关,与大于v的状态无关。可先更新大容量的状态值。
我自己的理解就是,想求现在v容量i件物品最大价值,而需要比较的是上一状态i-1件物品v容量的价值(i不放背包)和i-1件物品v-c[i]容量的价值(i放入背包)。所以不能先把小容量的状态值修改了,否则会影响这一个状态寻找最大值。
链接:
01背包,C题
01背包,D题.
★完全背包:f[i][j]=max{f[i-1][j-k*w[i]]+k*v[i]|0=<k<=V/w[i]}
时间优化:
f[i][j]=max(f[i-1][j], f[i][j–wi]+vi) f[ i ][ v ]//为前 i 种物品恰好放入容量为 v 的背包的最大权值。
理解根据上述状态转移方程可知,假设的是子结果f[ i-1 ][ v-k*w[i] ]
中并没有选入第 i 种物品,所以我们需要逆序遍历(像0/1背包一样)来确保该前提;但是现在考虑“加选一件第 i 种物品”这种策略时,正需要一个可能已经选入第 i 种物品的子结果f[ i ][ v-w[i] ]
,于是当我们顺序遍历时,就刚好达到该要求。这种做法会省去一层循环,即第 i 种物品放入的件数k。
空间优化:
//伪代码
for i = 1..N
for v = 0..V
f[v] = max{f[v],f[v-w[i]] + val[ i ] };
理解考虑f[i][j]
时,由于是从前往后写,f[j]没被写入,它表示的是f[i-1][j],f[j-w[i]]已被写入,它表示的是f[i][j-w[i]]
那么,一维的 f[v]=max{f[v],f[v-w[i]]+v[i]}
恰好能表示是二维的f[i][v]=max{f[i-1][v],f[i][v-w[i]]+v[i]}
★多重背包:
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。(在完全背包的基础上,找到每件物品的最优个数从而就找到了最优解)
理解,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。
f[i][v]//表示前i种物品恰放入一个容量为v的背包的最大权值,则:f[i][v]=max{ f[ i-1 ][ v-k*w[i] ] + k*val[ i ] | 0<= k <= n[ i ]}
具体问题具体分析
★分组背包:
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。
//伪代码
for 所有的组k
for v=V..0//必须在i循环的外部,这样才能保证每一组最多一个物品
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
具体问题具体分析