1.​​题目链接​​。中文题目就不再说题意了。首先我们知道这个题目的意思就是给你n中物品,每种物品有重量,价值,数量这三个属性。然后给定一个数值的钱,问这些钱最可以买多少东西。其实和背包的思想是一样的,就是容量为V的背包最多可以装多少东西。

2.分析:这和我们之前说到的01背包和完全背包都是不一样的,因为01背包中物品只有一个,所以就是拿与不拿的问题,完全背包中物品的数量是无限的,所以就是拿多少个的问题,然而在这里似乎综合了这两个问题,物品的数量是任意的(注意:这里的任意指的是一个有限的值,一定不是一个无限的值,否则问题的求解会发生变化)。这种问题我们叫做多重背包。

3.关于多重背包的解法有很多种,我们这里就先看一个DP写法。DP的写法也是有好几种写法,我们就写个最简单的(不是因为我懒,是因为难的不会)。我们知道,在完全背包里,我们没有枚举物品的数量,而是通过改变循环的方向解决了转移的问题。但是这里我们就不能这样做了,显然,最直接的写法就是枚举这些属性。有三个属性就分三次枚举:首先第一层枚举物品的种类(其实仔细的想一下,在01背包中我们的第一层的枚举也是在枚举种类,因为每种物品只有一个)那么显然,第二层我们就应该枚举每一种物品的数量了,第三层当然就是价值了。注意这里就应该是倒着循环!知道了这些,转移的方程就很好写了,几乎和完全背包的没有区别。直接给出代码吧。

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;
int n, m;
const int N = 300;
int v[N], w[N], num[N];
int dp[N];
#pragma warning(disable:4996)
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &w[i], &v[i], &num[i]);
}
memset(dp, 0, sizeof(dp));
for (int i = 0; i < m; i++)
{
for (int j = 1; j <= num[i]; j++)
{
for (int k = n; k >= w[i]; k--)
{
dp[k] = max(dp[k], dp[k - w[i]] + v[i]);
}
}
}
printf("%d\n", dp[n]);

}
}