此文系阅读《背包问题九讲》之后的笔记 ,在此先此文作者表示敬意
简单01背包问题
考虑第i件物品放还是不放, 递推公式为:
f[i][v] = max{f[i-1][v], f[i-1][v-cost[i]] + weight[i]}
递推第i件物品时,必须知道i-1时的结果,所以用一维数组实现时,for循环倒退
#define N
#define V
int cost[N], weight[N];
for (i = 1; i <= N; ++i) {
for (v = V; v >= cost[i]; --v)
#define V
int cost[N], weight[N];
for (i = 1; i <= N; ++i) {
for (v = V; v >= cost[i]; --v)
f[v] = max{f[v], f[v-cost[i]] + wight[i]};
根据有么有要求背包刚好填满:
yes:初始化时除f[0] = 0;其他都初始化为无穷小
no: 都初始化为0
完全背包问题
每个物品可以放多次。

for (v = 0; v <= V; ++v)
f[v] = max{f[v], f[v-cost[i]] + wight[i]};
for (i = 1; i <= N; ++i) {
for (v = 0; v <= V; ++v)
f[v] = max{f[v], f[v-cost[i]] + wight[i]};
多重背包问题
每个物品有上界n[i], 和完全背包类似。
n[i]可以分为1、2、4、…… 2*k-1、n[i]-2^(k-1)系数乘以cost[i]。
原问题转化为了复杂度为O(V*Σlog n[i])的01背包问题 ,分成0..2^k-1和2^k..n[i]两段
for (i = 1; i < N; ++i) {
if (cost[i] * amount[i] >= V) {
CompletePack(cost[i], weight[i]);
return;
}
int k = 1;
while (k < amount[i]) {
ZeroOnePack(k*cost[i], k*weight[i]);
amount[i] = amount[i] - k;
k = k*2;
}
ZeroOnePack(amount[i]*cost[i], amount[i]*weight[i]);
if (cost[i] * amount[i] >= V) {
CompletePack(cost[i], weight[i]);
return;
}
int k = 1;
while (k < amount[i]) {
ZeroOnePack(k*cost[i], k*weight[i]);
amount[i] = amount[i] - k;
k = k*2;
}
ZeroOnePack(amount[i]*cost[i], amount[i]*weight[i]);
}
混合三种背包问题
前面三种背包的集合,
for i=1..N
if 第i件物品属于01背包
ZeroOnePack(c[i],w[i])
else if 第i件物品属于完全背包
CompletePack(c[i],w[i])
else if 第i件物品属于多重背包
MultiplePack(c[i],w[i],n[i])
if 第i件物品属于01背包
ZeroOnePack(c[i],w[i])
else if 第i件物品属于完全背包
CompletePack(c[i],w[i])
else if 第i件物品属于多重背包
MultiplePack(c[i],w[i],n[i])