牛客网链接: 题目链接
题目描述
输入1
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出1
2200
输入2
50 5
20 3 5
20 3 5
10 3 0
10 2 0
10 1 0
输出2
130
说明:
由第1行可知总钱数N为50以及希望购买的物品个数m为5;
第2和第3行的q为5,说明它们都是编号为5的物品的附件;
第4~6行的q都为0,说明它们都是主件,它们的编号依次为3~5;
所以物品的价格与重要度乘积的总和的最大值为10*1+20*3+20*3=130
解题思路
首先这是个背包,很容易看出来。
题眼在于对附件的处理,我一开始把附件和主件一视同仁,然后每次在选择附件时,关注主件是否被选择。
这样做的代价,就是需要开另一个数组储存每个节点选择的物品序列。
以上的方法适用于附件数目不定的条件下。(但是也挺抽象的)
本题附件最多只有2个,而且附件不能脱离主件,所以可以把附件直接加在主件的后面,变成了分组背包。
一个分组最多有四个物品,分别是:
- 主件
- 主件+附件1
- 主件+附件2
- 主键+附件1+附件2
这样我们就可以提前计算,每种情况的花费和重要度。
题解
#include <cstdio>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// 这个题的关键就在于对附件的处理
// 因为附件数量是有限的,所以直接把附件加在主件上
//**********附件无法单独存在,所以直接合并在主件里********
int main()
{
int n, m;
scanf("%d %d", &n, &m);
n /= 10;
//储存每种情况的花费
vector<vector<int>> price(61, vector<int>(3, 0));
//储存每种情况的重要度
vector<vector<int>> value(61, vector<int>(3, 0));
for (int i = 1; i <= m; i++)
{
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
x /= 10;
y*=x;
// 主
if (z == 0)
{
price[i][0] = x;
value[i][0] = y;
}
// 从
else
{
// 从1
if (price[z][1] == 0)
{
price[z][1] = x;
value[z][1] = y;
}
// 从2
else
{
price[z][2] = x;
value[z][2] = y;
}
}
}
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
// 背包
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
{
int a, b, c, d, e, f;
a = price[i][0];
b = value[i][0];
c = price[i][1];
d = value[i][1];
e = price[i][2];
f = value[i][2];
if (j >= a)
{
dp[i][j] = max(dp[i - 1][j], b + dp[i - 1][j - a]);
}
//如果没有这个else,dp[i][j]的值会保持0,再和后面比就错了
else
{
dp[i][j]=dp[i-1][j];
}
// 注意后面的是和dp[i][j]比较******
if (j >= a + c)
{
dp[i][j] = max(dp[i][j], b + d + dp[i - 1][j - a - c]);
}
if (j >= a + e)
{
dp[i][j] = max(dp[i][j], b + f + dp[i - 1][j - a - e]);
}
if (j >= a + c + e)
{
dp[i][j] = max(dp[i][j], b + d + f + dp[i - 1][j - a - c - e]);
}
//实现方式2
// dp[i][j] = j >= a ? max(dp[i-1][j-a] + b, dp[i-1][j]) : dp[i-1][j];
// dp[i][j] = j >= (a+c) ? max(dp[i-1][j-a-c] + b + d, dp[i][j]) : dp[i][j];
// dp[i][j] = j >= (a+e) ? max(dp[i-1][j-a-e] + b + f, dp[i][j]) : dp[i][j];
// dp[i][j] = j >= (a+c+e) ? max(dp[i-1][j-a-c-e] + b + d + f, dp[i][j]) : dp[i][j];
}
}
printf("%d\n", dp[m][n] * 10);
return 0;
}