1.概念解析
多重背包问题是一种动态规划问题,其核心在于如何在有限
数量的物品中选择,使得背包中的物品总价值最大,同时不超过背包的容量限制。
2.举例了解
宝物筛选
题目描述
终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物。
这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小 FF 的采集车似乎装不下那么多宝物。看来小 FF 只能含泪舍弃其中的一部分宝物了。
小 FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小 FF 有一个最大载重为 W W W 的采集车,洞穴里总共有 n n n 种宝物,每种宝物的价值为 v i v_i vi,重量为 w i w_i wi,每种宝物有 m i m_i mi 件。小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。
输入格式
第一行为一个整数 n n n 和 W W W,分别表示宝物种数和采集车的最大载重。
接下来 n n n 行每行三个整数 v i , w i , m i v_i,w_i,m_i vi,wi,mi。
输出格式
输出仅一个整数,表示在采集车不超载的情况下收集的宝物的最大价值。
输入输出样例
输入 #1
4 20
3 9 3
5 9 1
9 4 2
8 1 3
输出 #1
47
提示
对于 30 % 30\% 30% 的数据, n ≤ ∑ m i ≤ 1 0 4 n\leq \sum m_i\leq 10^4 n≤∑mi≤104, 0 ≤ W ≤ 1 0 3 0\le W\leq 10^3 0≤W≤103。
对于 100 % 100\% 100% 的数据, n ≤ ∑ m i ≤ 1 0 5 n\leq \sum m_i \leq 10^5 n≤∑mi≤105, 0 ≤ W ≤ 4 × 1 0 4 0\le W\leq 4\times 10^4 0≤W≤4×104, 1 ≤ n ≤ 100 1\leq n\le 100 1≤n≤100。
思路解析
建议先食用01背包问题模型讲解和【题解】—— [NOIP2005 普及组] 采药和完全背包模型讲解和【题解】——疯狂的采药。
有一种比较直接的方法。类似于完全背包
,只需要将枚举每件物品的件数那一层循环的限制条件改成k<=nums[i]&&k*a[i].weight<=j //nums[i]表示第i件物品的数量
就行了。但是这样的方法太过暴力,还有更好的方法吗?
其实,我们可以将这道题转换成01背包
。用上面的样例来说明。
4 20
3 9 3
5 9 1
9 4 2
8 1 3
我们可以将每一件物品铺平
,放到数组a
里面去。并不需要把它们当成一堆物品来处理。此时的a
数组如下(只展示某件物品的价值和编号(按输入顺序来定,编号不存储在a
数组中,展示出仅为了方便理解)):
编号 | 1 | 1 | 1 | 2 | 3 | 3 | 4 | 4 | 4 |
---|---|---|---|---|---|---|---|---|---|
价值 | 3 | 3 | 3 | 5 | 4 | 4 | 1 | 1 | 1 |
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
最后只需要按01背包
来处理就行了。
3.示例代码
#include<bits/stdc++.h>
using namespace std;
#define MAXM 1010//m的数据范围,可根据题目修改
#define MAXN 1010//n的数据范围,可根据题目修改
//m表示背包的重量,n表示物品的数量,dp[j]表示当前重量上限为j时的最大价值
int m, n, dp[MAXM], cnt;
struct object{
int weight, value;//储存每个物品的重量和价值
object(int _w = 0, int _v = 0) :weight(_w), value(_v) {};
}a[MAXN];
int main(){
scanf("%d%d", &m, &n);
for (int i = 1; i <= n; i++){//输入n个物品
int w, v, m;//存储当前物品的重量,价值和件数
scanf("%d%d", &w, &v, &m);
for (int j = 1; j <= n; j++)a[++cnt] = object(w, v);//展开
}
for (int i = 1; i <= cnt; i++)
for (int j = m; j >= a[i].weight; j--)
//枚举所有能装下a[i]的重量
dp[j] = max(dp[j], dp[j - a[i].weight] + a[i].value);
printf("%d\n", dp[m]);
return 0;
}
注意:以上代码不能通过此题。需要使用二进制
优化。这里由于篇幅关系就先不展开讨论。
喜欢就订阅此专辑吧!
【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。
欢迎扫码关注蓝胖子编程教育