洛谷P2623 物品选取【DP+混合背包】【黄】

该博客讨论了一个物品选取的问题,涉及甲、乙、丙三类物品,每类物品有不同的价值和体积属性。博主提供了输入输出样例,并解释了动态规划的解题思路,特别是对于甲类物品需要额外的循环处理。最后给出了代码实现。

Date:2022.03.22
题目描述
小X可以选择的物品有n样,一共分为甲乙丙三类:
1.甲类物品的价值随着你分配给他的背包体积变化,它的价值与分配给它的体积满足函数关系式,v(x) = Ax^2-Bx,A,B是每个甲类物品的两个参数。注意每个体积的甲类物品只有一个。
2.乙类物品的价值A和体积B都是固定的,但是每个乙类物品都有个参数C,表示这个物品可供选择的个数。
3.丙类物品的价值A和体积B也是固定的,但是每个丙类物品可供选择的个数都是无限多个。
你最终的任务是确定小X的背包最多能装有多大的价值上路。
输入格式
第一行两个整数n,m,表示背包物品的个数和背包的体积;
接下来n行,每行描述一个物品的信息。第一个整数x,表示物品的种类:
若x为1表示甲类物品,接下来两个整数A, B,为A类物品的两个参数;
若x为2表示乙类物品,接下来三个整数A,B,C。A表示物品的价值,B表示它的体积,C表示它的个数;
若x为3表示丙类物品,接下来两个整数A,B。A表示它的价值,B表示它的体积。
输出格式
输出文件仅一行为一个整数,表示小X的背包能装的最大价值。
输入输出样例
输入 #1复制
1 0
1 1 1
输出 #1复制
0
输入 #2复制
4 10
2 1 2 1
1 1 2
3 5 2
2 200 2 3
输出 #2复制
610
说明/提示
对于50%的数据,只有乙和丙两类物品;
对于70%的数据,1<=n<=100, 1<=m<=500,0<=A,B,C<=200;
对于100%的数据,1<=n<=100, 1<=m<=2000,0<=A,B,C<=200;

题意说明:甲类是分给每一个物品多少体积x,它的价值才是v(x)。什么垃圾题意。因此01背包时枚举分给当前物品多少体积,多一重循环。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PII;
const LL N = 2010,INF
### P5192 题目要求详解及简化说明 P5192 是一道 **背包问题** 相关的动态规划题目,题目名称为 **“小D的旅行”**。题目核心在于理解物品选择的限制条件,并在有限的背包容量下最大化价值。 #### 题意详解 题目给出一个背包,容量为 $ V $,以及 $ n $ 个物品,每个物品具有以下属性: - **体积** $ v_i $:表示该物品占用的空间。 - **价值** $ w_i $:表示该物品价值。 - **类别** $ c_i $:表示物品的类别,取值为 $ 0 $ 或 $ 1 $。 物品选取规则如下: - 对于类别为 $ 0 $ 的物品,**只能选一个**。 - 对于类别为 $ 1 $ 的物品,**可以选任意多个**(即完全背包模型)。 目标是选择物品,使得总体积不超过背包容量的前提下,总价值最大。 #### 题意简化 将问题拆解为两个子问题: 1. **类别为 0 的物品**:采用 **0-1 背包** 的处理方式,每个物品只能选一次。 2. **类别为 1 的物品**:采用 **完全背包** 的处理方式,每个物品可以选多次。 最终答案是将两种物品动态规划结果合并,求最大总价值。 #### 动态规划思路 定义状态 $ dp[j] $ 表示容量为 $ j $ 时的最大价值。 - 对于类别为 0 的物品,按照 0-1 背包的方式处理,**逆序遍历容量**: ```cpp for (int j = V; j >= v[i]; j--) dp[j] = max(dp[j], dp[j - v[i]] + w[i]); ``` - 对于类别为 1 的物品,按照完全背包的方式处理,**正序遍历容量**: ```cpp for (int j = v[i]; j <= V; j++) dp[j] = max(dp[j], dp[j - v[i]] + w[i]); ``` #### 示例代码 ```cpp #include <iostream> #include <vector> using namespace std; const int MAXV = 1005; int dp[MAXV]; int main() { int n, V; cin >> n >> V; for (int i = 0; i < n; ++i) { int v, w, c; cin >> v >> w >> c; if (c == 0) { // 0-1 背包,逆序更新 for (int j = V; j >= v; --j) dp[j] = max(dp[j], dp[j - v] + w); } else { // 完全背包,正序更新 for (int j = v; j <= V; ++j) dp[j] = max(dp[j], dp[j - v] + w); } } cout << dp[V] << endl; return 0; } ``` #### 解题关键点 - **状态转移的顺序**:0-1 背包必须逆序,完全背包必须正序。 - **合并两种类型物品**:先处理类别为 0 的物品,再处理类别为 1 的物品,或者交替处理。 - **初始化**:$ dp[0] = 0 $,其余初始化为 0 即可[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值