01背包
有 N件物品和一个容量为V的背包。第 i件物品的费用是w[i],价值是 v[i],求将哪些物品装入背包可使价值总和最大。
for (int i = 1; i <= n; i++)
for (int j = V; j >= w[i]; j–)
f[j] = max(f[j], f[j - w[i]] + v[i]);
完全背包
有 N种物品和一个容量为 V的背包,每种物品都有无限件可用。第 i i i种物品的费用是 w [ i ],价值是 v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
for (int i = 1; i <= n; i++)
for (int j = w[i]; j <= V; j++)
f[j] = max(f[j], f[j - w[i]] + v[i]);
细看之下,完全背包和01背包的区别就是物品是否无限,代码更是只有for循环的顺序不同,为什么这样一改就可以解决完全背包的问题了呢?
01背包按照j=V到0的逆序,是为了保证每种物品只取一次,第i次循环的f[i][j]就是由f[i-1][j-w[i]]递推而来,选第i件物品时,f[i-1][j-w[i]]没有选择过第i件物品
完全背包是每种物品有无限件,所以考虑的是加选第i件物品,需要的是一个已经选过第i件物品的状态f[i-1][j-w[i]]就必须采用j=0到V的策略
首先说完全背包的正序枚举
假设你现在有一个体积为V的背包,有一个体积为3,价值为4的物品,如果正序枚举的话,等我们填充到3这个位置,就会得到价值为4的物品,
等我们在填充到 6这个位置时,发现还可以造成更大的价值,也就是把这个物品再用一遍
这就是完全背包为什么体积正序枚举的原因
下面说01背包的倒序枚举
题目一样,此时倒序填充背包,为了方便从 6 开始
此时,在体积为6的背包中有了价值为4的物品,但体积为3的背包中物品的价值仍然为0,也就是说填充体积为6的背包只得到了填充体积为3的背包的价值,等再枚举到体积为3的背包时,我们才填充了体积为3的背包,接下来枚举物品是就不会再重复使用这个物品了,所以这个物品只被放了一次,最后的状态是这样的
多重背包问题
题目
有 N种物品和一个容量为 VV的背包。第 ii种物品最多有 p[i]件可用,每件费用是 w[i],价值是 v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本方法是转化为01背包求解:把第 i i i种物品换成 p [ i ]件01背包中的物品,则得到了物品数为 Σ p [ i ]的01背包问题,直接求解,复杂度仍然是O(V∗Σp[i])。但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第 i i i种物品换成若干件物品,使得原问题中第 i i i种物品可取的每种策略
for(i=0; i<n; i++)
{
c=1;
scanf("%d%d",&a,&b);//a是物品的个数,b是价值
//将个数拆分成1,2,4,8,16个
while(a>c)
{
w[k++]=cb;
a-=c;
c<<=1;
}
w[k++]=ab;
}
也可以将完全背包改一下
状态转移方程
f[i][j]=max(f[i−1][j−k∗w[i]]+k∗v[i])∣0<=k<=p[i]
混合背包问题
问题
如果将前面三个背包混合起来,也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包),应该怎么求解呢?
未完待续