P1064 金明的预算方案 - 背包问题

新博客地址:https://gyrojeff.top,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客👇

本文标题:P1064 金明的预算方案 - 背包问题

文章作者:gyro永不抽风

发布时间:2020年09月24日 - 12:09

最后更新:2020年09月24日 - 17:09

原始链接:http://hexo.gyrojeff.moe/2020/09/24/P1064-%E9%87%91%E6%98%8E%E7%9A%84%E9%A2%84%E7%AE%97%E6%96%B9%E6%A1%88-%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98/

许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 转载请保留原文链接及作者!

题目

题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 nn 元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 00 个、11 个或 22 个附件。每个附件对应一个主件,附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的 nn 元。于是,他把每件物品规定了一个重要度,分为 55 等:用整数 151 \sim 5 表示,第 55 等最重要。他还从因特网上查到了每件物品的价格(都是 1010 元的整数倍)。他希望在不超过 nn 元的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第 jj 件物品的价格为 vjv_j,重要度为wjw_j,共选中了 kk 件物品,编号依次为 j1,j2,,jkj_1,j_2,\dots,j_k,则所求的总和为:

vj1×wj1+vj2×wj2++vjk×wjkv_{j_1} \times w_{j_1}+v_{j_2} \times w_{j_2}+ \dots +v_{j_k} \times w_{j_k}

请你帮助金明设计一个满足要求的购物单。

输入格式

第一行有两个整数,分别表示总钱数 nn 和希望购买的物品个数 mm

22 到第 (m+1)(m + 1) 行,每行三个整数,第 (i+1)(i + 1) 行的整数 viv_ipip_iqiq_i 分别表示第 ii 件物品的价格、重要度以及它对应的的主件。如果 qi=0q_i=0,表示该物品本身是主件。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出 #1
2200

说明/提示

数据规模与约定

对于全部的测试点,保证 1n3.2×1041 \leq n \leq 3.2 \times 10^41m601 \leq m \leq 600vi1040 \leq v_i \leq 10^41pi51 \leq p_i \leq 50qim0 \leq q_i \leq m,答案不超过 2×1052 \times 10^5

题解

这道题可以只枚举主要物品,有五种选择方法:

  • 主 + 副1
  • 主 + 副2
  • 主 + 副1 + 副2
  • 不选

然后其实就是普通的背包问题了(撒花

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>

using namespace std;

const int maxm = 65;
const int maxn = 32005;

int pos[maxm], cnt[maxm], f[maxn];
struct node { int v, p; } a[maxm][3];

int main() {
int n, m, k = 0;
cin >> n >> m;
for (int i = 1; i <= m; i ++) {
int v, p, q; cin >> v >> p >> q;
if (q == 0) {
a[++ k][0] = (node) { v, p };
pos[i] = k;
} else a[pos[q]][++ cnt[q]] = (node) { v, p };
}
for (int i = 1; i <= k; i ++) {
for (int j = n; j >= a[i][0].v; j --) {
if (j >= a[i][0].v + a[i][1].v + a[i][2].v)
f[j] = max(f[j], f[j - (a[i][0].v + a[i][1].v + a[i][2].v)] + a[i][0].v * a[i][0].p + a[i][1].v * a[i][1].p + a[i][2].v * a[i][2].p);
if (j >= a[i][0].v + a[i][1].v)
f[j] = max(f[j], f[j - (a[i][0].v + a[i][1].v)] + a[i][0].v * a[i][0].p + a[i][1].v * a[i][1].p);
if (j >= a[i][0].v + a[i][2].v)
f[j] = max(f[j], f[j - (a[i][0].v + a[i][2].v)] + a[i][0].v * a[i][0].p + a[i][2].v * a[i][2].p);
if (j >= a[i][0].v)
f[j] = max(f[j], f[j - a[i][0].v] + a[i][0].v * a[i][0].p);
}
}
cout << f[n] << endl;
return 0;
}
posted @ 2020-11-10 17:54  gyro永不抽风  阅读(90)  评论(0编辑  收藏  举报