跳转至

一本通-1270:【例9.14】混合背包

【题目描述】 一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,Wn,它们的价值分别为C1,C2,...,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】 第一行:二个整数,M(背包容量,M≤200),N(物品数量,N≤30);

第2..N+1行:每行三个整数Wi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数件,若为其他数字,则为此物品可购买的最多件数(Pi)。

【输出】 仅一行,一个数,表示最大总价值。

【输入样例】 10 3 2 1 0 3 3 1 4 5 4

【输出样例】 11


#include <bits/stdc++.h>

using namespace std;

int n, m;
vector<int> dq_val(205), dq_pos(205), d(205);


void zeroOnePack(int weight, int value)
{
    for (int i = m; i >= weight; --i)
        d[i] = max(d[i], d[i - weight] + value);
}

void completePack(int weight, int value)
{
    for (int i = weight; i <= m; ++i)
        d[i] = max(d[i], d[i - weight] + value);
}

void multiPack(int weight, int value, int num)
{
    //fill(dq_pos.begin(), dq_pos.end(), 0);
    //fill(dq_val.begin(), dq_val.end(), 0);

    for (int a = 0; a < weight; ++a) {
        int start = 0, end = 0;
        for (int j = 0; j * weight + a <= m; ++j) {
            int tmp = d[a + j * weight] - j * value;
            while (start < end && dq_val[end - 1] <= tmp) --end;
            dq_pos[end] = j;
            dq_val[end++] = tmp;
            d[j * weight + a] = dq_val[start] + j * value;
            if (dq_pos[start] == j - num) ++start;
        }
    }
}


int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> m >> n;
    int weight, value, num;
    for (int i = 0; i < n; ++i) {
        cin >> weight >> value >> num;
        if (num == 0) completePack(weight, value);
        else if (num == 1) zeroOnePack(weight, value);
        else multiPack(weight, value, num);
    }
    cout << d[m] << endl;

    return 0;
}