【模板】动态规划的背包问题

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]);
01背包

完全背包:

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件物品就变成了logk件,再做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 }
多重背包二进制优化

猜你喜欢

转载自www.cnblogs.com/devilk-sjj/p/9065591.html