刷题记录:牛客NC14704美味菜肴

传送门:牛客

题目描述:

题目较长此处省略
输入:
1 1 74
2
1 502 47
输出:
408

自我感觉这道题还是挺难处理的(虽然代码不长,但是毕竟四星),经过了这道题感觉自己对于 01 背包 01背包 01背包的理解更上一层楼了

主要思路:

  1. 感觉每一个人首先看到这道题肯定都会想到01背包,但是感觉直接套又有点问题.首先我们会发现我们的价值是会随着我们的时间改变的,所以假设我们直接套01背包的代码的话就会发现我们的 d p [ t ] dp[t] dp[t]显然不是最优的,因为我们当前的物品放的越早我们的价值就是越高的.但是这个问题也不难解决,只要枚举一遍我们的时间即可
  2. 其次,因为我们的题目中要求的是至少有一个菜肴,并且我们的价值是可以为负的,所以我们应该将我们的dp数组全部赋值为-inf,然后将我们的 d p [ 0 ] = 0 dp[0]=0 dp[0]=0,这样的话就可以保证我们至少应该有一个菜肴会被选进来
  3. 当我们想完前两点之后我们这个代码其实还是有bug的,因为我们的菜肴是与我们的时间有关的,也就是说假设我们从 1 菜肴转移到我们的 2 菜肴 1菜肴转移到我们的2菜肴 1菜肴转移到我们的2菜肴与我们 2 菜肴转移到 1 菜肴 2菜肴转移到1菜肴 2菜肴转移到1菜肴,这两个转移最终的答案肯定是不一样的,但是我们在上述的背包里并没有考虑这一点.所以我们需要考虑这一点.也就是尽量的让更加优的菜肴先放在前面,也就是先进背包
  4. 对于两个物体 A, B, 先取 A 物体比先取 B 物体优
    当且仅当
    a i − b i ∗ c i + a j − b j ∗ ( c i + c j ) a_i -b_i * c_i + a_j - b_j * (c_i + c_j) aibici+ajbj(ci+cj) > > > a j − b j ∗ c j + a i − b i ∗ ( c i + c j ) a_j - b_j * c_j + a_i - b_i * (c_i +c_j) ajbjcj+aibi(ci+cj)

化解一下就是 b j ∗ c i < b i ∗ c j b_j * c_i < b_i * c_j bjci<bicj
然后我们直接根据上述sort一下即可

下面是具体的代码部分:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x = 0, w = 1;
	char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps = 1e-8;
int n, m, t;
ll dp[1000010];int b[maxn];
struct Food{
	int j,a,c;
}food[maxn];
bool cmp(Food aa,Food bb) {
	return b[aa.j]*bb.c>b[bb.j]*aa.c;
}
int main() {
	n = read();
	m = read();
	t = read();
	for (int i = 1; i <= n; i++) b[i]=read();
	for (int i = 1; i <= m; i++) {
		food[i].j=read();food[i].a=read();food[i].c=read();
	}
	sort(food+1,food+1+m,cmp);
	ll ans=-ll_maxn;
	memset(dp,-0x3f,sizeof(dp));
	dp[0]=0;
	for (int k = 1; k <= m; k++) {
		for (int i = t; i >= food[k].c; i--) {
			dp[i] = max(dp[i], dp[i - food[k].c] + food[k].a - i * b[food[k].j]);
			ans=max(ans,dp[i]);
		}
	}
	cout << ans << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值