【笔记】【算法学习】【动态规划】背包问题总结(1)
(1)0/1背包
For i:=1 to n do
For j:=vtot downto v[i] do
F[j]:=max(f[j-v[i]]+w[i],f[j]);
如果题目要求恰好装满背包,则f数组除了f[0]初始化为0之外,其他的初始化为-maxlongint;
(2)完全背包(每个物品有无限件可用)
for i:=1 to n do
for j:=v[i] to vtot do
f[j]:=max(f[j],f[j-v[i]]+w[i]);
(3)多重背包(每个物品有有限件可以用)
Porocedure init;
Var
X,y,z,i:longint;
Begin
Readln(x,y,z);
I:=1;
While i<z do
Begin
Inc(tt);
V[tt]:=x*I;
W[tt]:=y*I;
Dec(z,i);
I:=i*2;
End;
Inc(tt);
V[tt]:=x*z;
W[tt]:=y*z;
End;
01背包
(4)混合背包
对所有多重背包拆分
For i:=1 to n do
If 当前物品是01背包……
If 当前物品是完全背包……
(5)多维费用背包
在方程上加一维即可
方法同上
这里不再写
物品总个数的限制
有时,“二维费用”的条件是以这样一种隐含的方式给出的:最多只能取M件物品。这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为1,可以付出的最大件数费用为M。换句话说,设f[v][m]表示付出费用v、最多选m件时可得到的最大价值,则根据物品的类型(01、完全、多重)用不同的方法循环更新,最后在f[0..V][0..M]范围内寻找答案。注:只要是01背包,不管几维都要倒序循环
(6) 分组背包
for 所有的组k
for v=V..0
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}
注意这里的三层循环的顺序, “for v=V..0”这一层循环必须在“for 所有的i属于组k”之外。这样才能保证每一组内的物品最多只有一个会被添加到背包中。
(7)求方案总数
对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是完全背包中的物品,转移方程即为
f[i][v]=sum{f[i-1][v],f[i][v-c[i]]}
初始条件f[0][0]=1。
(8)求最优方案总数
这里的最优方案是指物品总价值最大的方案。以01背包为例。
结合求最大总价值和方案总数两个问题的思路,最优方案的总数可以这样求:f[i][v]意义同前述,g[i][v]表示这个子问题的最优方案的总数,则在求f[i][v]的同时求g[i][v]的伪代码如下:
for i=1..N
for v=0..V
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
g[i][v]=0
if(f[i][v]==f[i-1][v])
inc(g[i][v],g[i-1][v])
if(f[i][v]==f[i-1][v-c[i]]+w[i])
inc(g[i][v],g[i-1][v-c[i]])
{考虑一下一维的如何实现}
我发现背包这个东西真的是好强大,和以前看的感觉完全不一样,今天先写到这里吧,明天我会继续写的。
加油!