题目大意
- 知道时间 t ,有n 株备选药品,采摘一株需要用时 v,价值 w;
- 有部分药品,需要有前置条件;
- 求 t 时间内,能采摘的最大价值的药;
题目分析
- 这还是一道组合的问题:
- 分析样例:1000秒的时间,有5株药可选,暴力的做法应该是:
- 用 i 表示当前可以放进箱子的物品总数量不等,部分还有从属关系,
- 这是一个似乎比5选x 更复杂的组合问题。
- 但是因为体积和物体种类都会远远超过可承受的枚举范围,所以要想优化:
解题思路:
- 题目要求知道最优状态,所以可以忽略过程;
- 降维分析,因为只考虑物体的体积,不考虑形状等乱七八糟的东西,用打表:
- 用递推的思维,反向枚举时间的消耗,得到最优解。
代码:
//luogu1064:金明的预算方案
//带从属关系的背包问题
//先将所有的从属关系理顺
//再做背包
#include<bits/stdc++.h>
using namespace std;
int a[32005][5],b[32005][5];
int f[200005];
int n,v;
int maxx(int x,int y) { return x>y?x:y; }
int main()
{
scanf("%d %d",&v,&n);
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
int t,w,k;
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&t,&w,&k);
if(k==0)//是主件
{
a[i][0]=t*w;b[i][0]=t;
}
else if(a[k][1]==0)//第一个 附件
{
a[k][1]=t*w;b[k][1]=t;
}
else if(a[k][2]==0)//第二个 附件
{
a[k][2]=t*w;b[k][2]=t;
}
}
for(int i=1;i<=n;i++)
{
if(a[i][0]==0) continue;//附件直接跳过,只处理主件
t=b[i][0];
for(int j=v;j>=t;j--)
{
f[j]=maxx(f[j],f[j-t]+a[i][0]);//只取主件
if(a[i][1]!=0&&j-t-b[i][1]>=0) //取1号附件
f[j]=maxx(f[j],f[j-t-b[i][1]]+a[i][0]+a[i][1]);
if(a[i][2]!=0&&j-t-b[i][2]>=0) //取2号附件
f[j]=maxx(f[j],f[j-t-b[i][2]]+a[i][0]+a[i][2]);
if(a[i][2]!=0&&j-t-b[i][1]-b[i][2]>=0) //同时取1和2号附件
f[j]=maxx(f[j],f[j-t-b[i][1]-b[i][2]]+a[i][0]+a[i][1]+a[i][2]);
}
}
printf("%d",f[v]);
return 0;
}