luogu1064:金明的预算方案:01背包ex

题目连接

  • 该题是luogu试炼场的2-15:T3

题目大意

  1. 知道时间 t ,有n 株备选药品,采摘一株需要用时 v,价值 w;
  2. 有部分药品,需要有前置条件;
  3. 求 t 时间内,能采摘的最大价值的药;

题目分析

  • 这还是一道组合的问题:
  • 分析样例:1000秒的时间,有5株药可选,暴力的做法应该是:
  1. 用 i 表示当前可以放进箱子的物品总数量不等,部分还有从属关系,
  2. 这是一个似乎比5选x 更复杂的组合问题。
  • 但是因为体积和物体种类都会远远超过可承受的枚举范围,所以要想优化:


解题思路:

  1. 题目要求知道最优状态,所以可以忽略过程;
  2. 降维分析,因为只考虑物体的体积,不考虑形状等乱七八糟的东西,用打表:
  3. 用递推的思维,反向枚举时间的消耗,得到最优解。

代码:

//luogu1064:金明的预算方案 

//带从属关系的背包问题
//先将所有的从属关系理顺
//再做背包 

#include
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;
}

你可能感兴趣的:(题解,luogu,题表,大礼包,luogu1064,01背包,从属背包)