流浪西邮之寻找火石碎片(01背包变形)

题目描述
众所周知,由于木星引力的影响,世界各地的推进发动机都需要进行重启。现在你接到紧急任务,要去收集火石碎片,重启西邮发动机。现在火石碎片已成为了稀缺资源,获得火石碎片需要钱或者需要一定的积分。火石碎片有大有小,越大的碎片能量越大,火石碎片的能量越大,重启的发动机的推力也就越强。但是,不只有我们在努力呀,隔壁的师大和政法也都在收集碎片,争取重启师大发动机和政法发动机,哪个高校重启的发动机推力最大,就能代表长安区大学城为世界做出贡献,从而在史书上留下浓墨重彩的一笔。
现在你有v1块钱,v2积分,能免费(免积分)收集k个火石碎片,现在总共有n个火石碎片,每个碎片需要的钱a或者积分b,碎片的能量为val。我们希望收集火石碎片,使能量的总和尽可能大,问你skyer_hxx最多可以拿到能量总和的最大值是多少?

输入
输入包含多组测试用例。
每组数据的第一行是四个整数n,v1,v2,k;
然后是n行,每行三个整数a,b,val,分别表示每个碎片的价钱,兑换所需积分,所含能量。
1≤n≤100
0≤v1,v2≤100
0≤k≤5
0≤a,b,val≤100

输出
对于每组数据,输出能得到的最大能量值。

样例输入
复制样例数据
4 5 2 1
2 2 4
4 5 1
4 2 4
2 2 5
样例输出
14

思路:每个碎片只能选一次,很明显是01背包变形,需要从大到小遍历
dp[j][k][m]表示在钱数为j,积分为k,剩余免费碎片数m的情况下的最大价值。
四重循环,找到最大价值。

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 105;
int a[N];
int b[N];
int v[N];
int dp[N][N][10];
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		int x,v1,v2;
		memset(dp,0,sizeof(dp));
		scanf("%d%d%d",&v1,&v2,&x);
		for(int i=1;i<=n;i++)
			scanf("%d%d%d",&a[i],&b[i],&v[i]);
		for(int i=1;i<=n;i++)  //枚举每种物品
			for(int j=v1;j>=0;j--)  //枚举钱数
				for(int k=v2;k>=0;k--)  //枚举积分数
					for(int m=x;m>=0;m--)  //枚举剩余碎片数
					{
						if(j>=a[i])    //注意不能在循环中加这三个判断条件,因为判断条件并不唯一,在钱数不足的情况下可以用积分或者免费碎片机会来获得该价值
							dp[j][k][m]=max(dp[j][k][m],dp[j-a[i]][k][m]+v[i]);
						if(k>=b[i])
							dp[j][k][m]=max(dp[j][k][m],dp[j][k-b[i]][m]+v[i]);
						if(m>=1)
							dp[j][k][m]=max(dp[j][k][m],dp[j][k][m-1]+v[i]);
					}
		cout<<dp[v1][v2][x]<<endl;
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43693379/article/details/94391794