01背包:
n件物品,背包最大载重为W,第i件物品的重量为w[i],价值为v[i],求在不超过W的情况下背包内物品价值的最大总和。
状态转移方程:
f[j] = max(f[j], f[j - w[i]] + v[i])
1≤i≤n, w[i]≤j≤W
1 for(int i=1; i<=n; ++i) 2 for(int j=W; j>=w[i]; --j) 3 f[j] = max(f[j], f[j - w[i]] + v[i]);
完全背包:
n种物品,每种物品可以选无数次,
背包最大载重为W,第i种物品的重量为w[i],价值为v[i],求在不超过W的情况下背包内物品价值的最大总和。
DP方程和01背包的一样,只不过循环顺序要从逆序变成正序
1 for(int i=1; i<=n; ++i) 2 for(int j=w[i]; j<=W; ++j) 3 f[j] = max(f[j], f[j - w[i]] + v[i]);
多重背包:
n种物品,每种物品有p[i]个,
背包最大载重为W,第i种物品的重量为w[i],价值为v[i],求在不超过W的情况下背包内物品价值的最大总和。
DP方程还是和01背包一样,不过要在第二层加一个p[i]次的循环,表示这一件物品要选p[i]次
1 for(int i=1; i<=n; ++i) 2 for(int k=1; k<=p[i]; ++k) 3 for(int j=W; j>=w[i]; --j) 4 f[j] = max(f[j], f[j - w[i]] + v[i]);
多重背包的二进制优化:
把k拆成1 + 2 + 4 + 8 + ... + 2n + x的形式,这样原来的k件物品就变成了log2 k件,再做01背包就好
1 int main() { 2 n = read(), W = read(); 3 int cnt = 0; 4 for(int i=1; i<=n; ++i) { 5 w[i] = read(), v[i] = read(), p[i] = read(); 6 int s = 1; 7 while(p[i] > s) { 8 ww[++cnt] = w[i] * s; 9 vv[cnt] = v[i] * s; 10 p[i] -= s; 11 s <<= 1; 12 } 13 if(p[i]) { 14 ww[++cnt] = w[i] * p[i]; 15 vv[cnt] = v[i] * p[i]; 16 } 17 } 18 for(int i=1; i<=cnt; ++i) 19 for(int j=W; j>=ww[i]; --j) 20 f[j] = max(f[j], f[j - ww[i]] + vv[i]); 21 }