多重背包。
一道带有历史的题啊,沉重的回忆。
多重背包的处理关键就是将每种物品的可取个数二进制化,比如一种物品最多取7
件,那么就可以转化为3
件物品(其中每件物品相当于1
,2
,4
件单位物品),这样包含了取原先物品的任何一种情况(0~7
件),并且在求解效率上优于转化为7
件相同物品(本质是从O(n)到O(log n)的提升)。
以上这个方法务必掌握,除此之外,如果只取一种物品都能装满背包(或者更多),那么这种物品相当于没有上限了(完全背包),不用再转化了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
using namespace std; // 多重背包
const int MAX = 101;
int T, N, V;
int p[MAX];
int w[MAX];
int c[MAX];
int dp[101];
vector<int> t;
void init()
{
memset(dp, 0, sizeof dp);
}
int main()
{
scanf("%d", &T);
for (; T--;)
{
scanf("%d%d", &V, &N);
init();
for (int i = 1; i <= N; i++)
scanf("%d%d%d", &w[i], &p[i], &c[i]);
for (int i = 1; i <= N; i++)
{
if (c[i] * w[i] >= V) // 直接调用完全背包
{
for (int j = w[i]; j <= V; j++)
{
dp[j] = max(dp[j], dp[j - w[i]] + p[i]);
}
}
else
{
t.clear();
for (int k = 1; k < c[i]; k <<= 1) // 二进制处理,分成多个01背包
{
t.push_back(k);
c[i] -= k;
}
t.push_back(c[i]);
for (int k = 0; k < t.size(); k++)
{
for (int j = V; j >= w[i] * t[k]; j--)
{
dp[j] = max(dp[j], dp[j - w[i] * t[k]] + p[i] * t[k]);
}
}
}
}
printf("%d\n", dp[V]);
}
return 0;
}