一本通-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;
}