# 题目大意有 n n n 种物品和一个容量是 v v v 的背包 第 i i i 种物品的体积是 v i v_i v i ,价值是 w i w_i w i ,有 s i s_i s i 件 问:你放进背包的最大价值是多少
# 数据范围小范围(多重背包 I I I )0 < N , V ≤ 1000 0 < N, V \le 1000 0 < N , V ≤ 1 0 0 0 0 < v i , w i ≤ 1000 0 < v_i, w_i \le 1000 0 < v i , w i ≤ 1 0 0 0 大范围(多重背包 I I II I I )0 < N ≤ 1000 0 < N \le 1000 0 < N ≤ 1 0 0 0 0 < V ≤ 2000 0 < V \le 2000 0 < V ≤ 2 0 0 0 0 < v i , w i ≤ 2000 0 < v_i, w_i \le 2000 0 < v i , w i ≤ 2 0 0 0 # 思路# 小范围对于小范围的多重背包,直接类似完全背包的三维思路,将第三维改成枚举 k k k 个第 i i i 种物品即可
C++ 1 2 3 4 5 6 7 8 9 10 11 12 void solve () { cin >> n >> m; for (int i = 1 ; i <= n; i++) cin >> v[i] >> w[i] >> s[i]; for (int i = 1 ; i <= n; i++) for (int j = 0 ; j <= m; j++) for (int k = 0 ; j >= k * v[i] && k <= s[i]; k++) dp[i][j] = max (dp[i][j], dp[i - 1 ][j - k * v[i]] + k * w[i]); cout << dp[n][m] << endl; }
# 大范围对于大范围的多重背包,应将多重背包进行二进制拆分,从而转换成 01 01 0 1 背包
对于任意一个数 n n n ,他一定能分解成n = 1 + 2 1 + 2 2 + . . . + 2 t + r e s n = 1 + 2^1 + 2^2 + ... + 2^t + res n = 1 + 2 1 + 2 2 + . . . + 2 t + r e s 而对于 1 → n 1 \to n 1 → n 的任意一个数,都能从这里面抽若干个构成,从而可以构成 01 01 0 1 背包
利用 01 01 0 1 背包的一维写法,得出以下代码
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void solve () { cin >> n >> m; for (int i = 1 , vv, ww, ss; i <= n; i++) { cin >> vv >> ww >> ss; int t = 1 ; while (t <= ss) ++cnt, v[cnt] = t * vv, w[cnt] = t * ww, ss -= t, t *= 2 ; if (ss > 0 ) ++cnt, v[cnt] = ss * vv, w[cnt] = ss * ww; } n = cnt; for (int i = 1 ; i <= n; i++) for (int j = m; j >= v[i]; j--) dp[j] = max (dp[j], dp[j - v[i]] + w[i]); cout << dp[m] << endl; }