01背包 多重背包 T3

4877. 最大价值 - AcWing题库

AcWing,第96场周赛

有一个容量为 的背包和 种物品,每种物品都有无限多个。

物品种类编号为

种物品的体积为 ,价值为

在使用背包装入物品时,每种物品的限重如下:

  • 种物品:重量忽略不计,在装入时没有重量限制。
  • 种物品:第 种物品的单个重量为 ,如果该种物品的装入总重量超过 ,则视为超重。

现在,请你挑选物品装入背包,要求

  • 所有装入物品的总体积不得超过背包容量。
  • 所有存在重量限制的物品均不得超重。
  • 满足以上所有条件的前提下,所有装入物品的总价值尽可能大。

输出总价值的最大可能值。

注意审题,不要将 的含义弄混。

输入格式

第一行包含四个整数

接下来 行,每行包含四个整数

输出格式

一个整数,表示总价值的最大可能值。

数据范围

个测试点满足
所有测试点满足

输入样例1:

10 2 2 1
7 3 2 100
12 3 1 10

输出样例1:

241

输入样例2:

100 1 25 50
15 5 20 10

输出样例2:

200

思路

有两个限制, 一个是体积-容量, 另一个是重量限制。并给了两种物品, 一种是忽略重量可以选择无限个(完全背包), 另一种是选的数量不能超过对应的 , 显然第二种就是每个物品选有限个(多重背包)。

算是 混合背包问题 的一个简化版。

先读入第一种物品, 然后用完全背包的方式处理掉, 接着读入第二种, 再用多重背包做一遍, 这样得出的f数组就是最后的答案。

也可以化为01背包, 第一种物品只有一个, 那么他最多选的个数不能超出容量, 把其复制对应份数, 再进行01背包也是可以得到正确结果。 多重背包的部分同理, 也可以化为01背包。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
const int N = 1e4, M = 1e3 + 10;
int f[M];
int v[N], w[N], cnt;
 
int main()
{
    int n, m, v0, w0;
    cin >> m >> n >> v0 >> w0;
    for(int j = 0; j < m / v0; j++) v[cnt] = v0, w[cnt++] = w0;
    
    for(int i = 0; i < n; i++)
    {
        int l, h, v1, w1;
        cin >> l >> h >> v1 >> w1;
        for(int j = 0; j < l / h; j++)
            v[cnt] = v1, w[cnt++] = w1;
    }
    
    for(int i = 0; i < cnt; i++)
    {
        for(int j = m; j >= v[i]; j--)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    }
    
    int res = 0;
    for(int i = 0; i <= m; i++) res = max(res, f[i]);
    cout << res << endl;
    
    return 0;
}