洛谷P1417 烹调方案(01背包+贪心)

题意:n个物品,T个时刻,每个物品只能制作一次,制作需要ci的时间,在t时刻完成第i样物品可以得到ai−t∗bi的价值,问在T的时间内最多能得到多少价值。

详解见博客:https://www.cnblogs.com/BCOI/p/8999396.html
这道题长得很像01背包,但是单纯按01背包去做肯定是错的,因为哪样物品先做,哪样物品后做是会影响最终价值的,也就是与做的顺序有关。这里很容易想到一个贪心,就是将物品按b从大到小排。但是这个贪心方案是错误的,给这样一个样例:
74 3
502 100 402
2 4 1
43 20 11
输出为764,正确答案为785。
那我们要怎么排序呢?考虑i,j两件物品,在t时刻先选择i或j时的方案能够获得的价值。
先选择i: a[i] - b[i] * (t - c[j]) + a[j] - b[j] * t ①
先选择j: a[j] - b[j] * (t - c[i]) + a[i] - b[i] * t ②
若①>②,即先选i时价值更大,此时将①>②化简后,得应满足条件:
b[i] * c[j] > b[j] * c[i]
于是,贪心方案出炉了:按照b[i] * c[j]从大到小排序。
代码如下:

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<stack>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll dp[maxn];
struct food
{
	ll a,b,c;
	double d;
}f[55];

bool cmp(food x,food y)
{
	return x.b*y.c>y.b*x.c;
}

int main()
{
	int T,n;
	cin>>T>>n;
	for(int i=1;i<=n;++i)	cin>>f[i].a;
	for(int i=1;i<=n;++i)	cin>>f[i].b;
	for(int i=1;i<=n;++i)	cin>>f[i].c;
	sort(f+1,f+1+n,cmp);
	mem(dp,0);
	for(int i=1;i<=n;++i)
		for(int j=T;j>=f[i].c;--j)
			dp[j]=max(dp[j],dp[j-f[i].c]+f[i].a-j*f[i].b);
	ll ans=0;
	for(int i=0;i<=T;++i)	ans=max(ans,dp[i]);
	cout<<ans<<endl;
	return 0;
 } 

PS:其实我本人是在看了题目标签中,有排序二字后,突然想到可以试试按照b/c从大到小排序,结果交了一遍真的AC了,然而表示并不知道为什么得这么做,是看了上面的博客才知道的。
小结:其实这道题的贪心方案推导也不算太难,只要动动脑,动动手,可能就能够搞出来。另外头一回遇到DP与贪心混一块的题,我还以为两者是对立的呢…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值