多重背包问题Ⅰ
题目描述 有 $N$ 种物品和一个容量是 $V$ 的背包。
第 $i$ 种物品最多有 $s_i$ 件,每件体积是 $v_i$,价值是 $w_i$。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。
输入格式
第一行两个整数 $N,V$,用空格隔开,分别表示物品种数和背包容积。
接下来有 $N$ 行,每行三个整数 $v_i,w_i,s_i$,用空格隔开,分别表示第 $i$ 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
$0 \lt N, V \le 100$ $0 \lt v_i, w_i, s_i \le 100$
输入样例
1 2 3 4 5 4 5 1 2 3 2 4 1 3 4 3 4 5 2
输出样例:
题目求解 方式一 三重for循环求解 相比$01$背包问题增加一层循环对物品的多种可选方式$s_i$进行遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <algorithm> #include <cstring> using namespace std;const int N = 110 ;int n, m, f[N][N], v, w, s;int main () { cin >> n >> m; for (int i = 1 ; i <= n ;i ++) { cin >> v >> w >> s; for (int j = 0 ; j <= m ;j ++) { f[i][j] = f[i - 1 ][j]; for (int k = 0 ; k <= s && j >= k * v; k ++) { f[i][j] = max (f[i][j] , f[i - 1 ][j - k * v] + k * w); } } } cout << f[n][m]; }
滚动数组的优化,将二维数组优化为一维数组,相当于代码的等价变形,时间复杂度$O(n \times m \times s)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <algorithm> #include <cstring> using namespace std;const int N = 110 ;int n, m, f[N], v, w, s;int main () { cin >> n >> m; for (int i = 1 ; i <= n ;i ++) { cin >> v >> w >> s; for (int j = m ; j >= 0 ;j --) { for (int k = 1 ; k <= s && j >= k * v; k ++) { f[j] = max (f[j] , f[j - k * v] + k * w); } } } cout << f[m] << endl; }
方式二 转换为01背包问题求解 将所有的商品包括重复的商品当作一个商品来看,这就转换成了$01$背包问题,时间复杂度$O(n \times m \times s)$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <algorithm> #include <cstring> using namespace std;const int N = 110 ;const int M = 10010 ;int n, m, f[N], v, w, s, V[M], W[M], t;int main () { cin >> n >> m; while (n --) { cin >> v >> w >> s; while (s --) { V[++t] = v; W[t] = w; } } for (int i = 1 ; i <= t; i ++) for (int j = m; j >= V[i] ; j --) f[j] = max (f[j], f[j - V[i]] + W[i]); cout << f[m] << endl; return 0 ; }