xixi_bang @ 2020-04-05 13:47:32
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m;
int f[5000010],h[5000010];
struct node
{
int v,p,q;
}a[1010];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].v,&a[i].p,&a[i].q);
a[i].p*=a[i].v;
}
for(int i=1;i<=m;i++)
if(!a[i].q)
{
for(int j=1;j<a[i].v;j++)
h[j]=0;
for(int j=a[i].v;j<=n;j++)
h[j]=f[j-a[i].v]+a[i].p;
for(int j=1;j<=m;j++)
if(a[j].q==i)
for(int k=n;k>=a[i].v+a[j].v;k--)
h[k]=max(h[k],h[k-a[j].v]+a[j].p);
for(int j=a[i].v;j<=n;j++)
f[j]=max(f[j],h[j]);
}
printf("%d\n",f[n]);
return 0;
}
在@Jackpei 大佬的解法中,我有一些问题,球球大佬们帮我解答一下QAQ 这里的f和h数组分别是干嘛的啊
by metaphysis @ 2020-04-05 19:57:54
@xixi_bang
本题可以归结为背包问题。背包问题有四种基本类型,分列如下(参见我写的书 《C++,挑战编程——程序设计竞赛进阶训练指南》 第 11 章“动态规划”第 11.1 节“背包问题”的内容):
基本背包问题:
给定一个容量为
完全背包问题:
给定一个容量为
多重背包问题:
给定一个容量为
部分背包问题:
给定一个容量为
前三种背包问题可以使用动态规划解决,最后一种部分背包问题可以通过贪心算法解决。
从题目的约束来看,属于基本背包问题的一种变形。预算
以上是解题思路的概述,如果您大致理解了,可以继续参考以下的代码注释进行理解。
// 读入 m 种物品的价格、重要度,第 i 种物品的价值为其价格和重要度的乘积。
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &a[i].v, &a[i].p, &a[i].q);
a[i].p *= a[i].v;
}
// 逐个物品考虑是否放入背包。
for(int i = 1; i <= m; i++)
// 题目的特殊限制:必须先放主件。当 a[i].q 为 0 时表示主件。
if(!a[i].q)
{
// 初始化 h 数组,因为第 i 种物品的价格为 a[i].v,
// 所以当预算小于 a[i].v 时,能够得到的最大价值为 0。
for(int j = 1; j < a[i].v; j++) h[j] = 0;
// 考虑购买该种主件,在原有的最优值数组 f 上更新得到最优值数组 h。
for(int j = a[i].v; j <= n; j++) h[j] = f[j - a[i].v] + a[i].p;
// 考虑购买主件的附件。
for(int j = 1; j <= m; j++)
// 检查当前物品是否为主件 i 的附件。
if(a[j].q == i)
// 检查放入附件 j 是否能够更新最优值。注意容量 k 的枚举顺序和下限值。
// k 从大到小枚举可以节省动态规划状态数组的一维存储空间。
// 参见我写的书 [《C++,挑战编程——程序设计竞赛进阶训练指南》]
// 第 11 章“动态规划”第 11.9 节“动态规划的优化”第
// 11.9.1 小节“空间优化”的内容。
for(int k = n; k >= a[i].v + a[j].v; k--)
h[k] = max(h[k], h[k - a[j].v] + a[j].p);
// 数组 h 存储的是考虑放入第 i 种主件及其附件后的最优值,
// 数组 f 存储的是不考虑放入第 i 种主件及其附件的最优值,
// 取两者的较优值。由于必须放入主件,故从 a[i].v 开始考虑更新。
for(int j = a[i].v; j<=n; j++) f[j] = max(f[j], h[j]);
}
// 输出最优值。
printf("%d\n",f[n]);
如果您有其他问题,欢迎您@我,如果时间允许的话,我很乐意提供帮助。
by xixi_bang @ 2020-04-05 20:37:23
@metaphysis 明白了!谢谢您这么耐心的解答!您实在很细心且逻辑清晰!之后有问题还烦请您指导!