for (int i = 1; i <= n; ++ i) for (int j = 0; j <= m; ++ j) { f[i][j] = f[i - 1][j]; if (v[i] <= j) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]); }
printf("%d", f[n][m]);
滚动数组优化
的计算只用到了 ,所以可以用滚动数组优化
1 2 3 4 5 6 7 8 9 10 11
int f[2][N];
for (int i = 1; i <= n; ++ i) { int now = i & 1, last = now ^ 1; for (int j = 0; j <= m; ++ j) { f[now][j] = f[last][j]; if (v[i] <= j) f[now][j] = max(f[now][j], f[last][j - v[i]] + w[i]); } }
printf("%d", f[n & 1][m]);
优化为一维
我们发现转移方程中 也就是说如果我们从后向前转移就不会有后效性
1 2 3 4 5
for (int i = 1; i <= n; ++ i) for (int j = m; j >= v[i]; -- j) f[j] = max(f[j], f[j - v[i]] + w[i]);
printf("%d", f[m]);
完全背包
每个物品可以选无限个
分析
起点
转移方程
终点
code
朴素版本
1 2 3 4 5 6
for (int i = 1; i <= n; ++ i) for (int j = 0; j <= m; ++ j) for (int k = 0; k * v[i] <= j; ++ k) f[i][j] = max(f[i][j], f[i- 1][j - k * v[i]] + k * w[i]);
cout << f[n][m] << endl;
优化
我们发现:
而:
所以有:
如果再加上以上所说的一维优化就有:
1 2 3 4 5
for (int i = 1; i <= n; ++ i) for (int j = v[i]; j <= m; ++ j) f[j] = max(f[j], f[j - v[i]] + w[i]);
for (int i = 1; i <= n; ++ i) for (int j = 0; j <= m; ++ j) for (int k = 0; k <= s[i] && k * v[i] <= j; ++ k) f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + w[i] * k);
#include<iostream> #include<cstring> #include<algorithm> #include<vector> usingnamespace std; constint N = 2010; int f[N]; structgood {int v, w; }; intmain(){ int n, m; vector<good> goods; scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++ i) { int v, w, s; scanf("%d%d%d", &v, &w, &s); for (int k = 1; k <= s; s -= k, k <<= 1) goods.push_back({k * v, k * w}); if (s) goods.push_back({s * v, s * w}); } for (auto [v, w]: goods) for (int j = m; j >= v; -- j) f[j] = max(f[j], f[j - v] + w); cout << f[m] << endl; }
#include<iostream> #include<cstring> #include<algorithm> usingnamespace std; constint N = 110; int n, m; int v[N][N], w[N][N], s[N]; int f[N]; intmain(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++ i) { scanf("%d", s + i); for (int j = 1; j <= s[i]; ++ j) scanf("%d%d", &v[i][j], &w[i][j]); } for (int i = 1; i <= n; ++ i) for (int j = m; j; -- j) for (int k = 1; k <= s[i]; ++ k) if (v[i][k] <= j) f[j] = max(f[j], f[j - v[i][k]] + w[i][k]); printf("%d", f[m]); }