最好的方案(dp,一个好用技巧)
Jane是一位富有冒险精神的火星人,他驾驶着自己的飞船穿越星际,向传说中的地球进发。然而,在飞船穿越茫茫宇宙的旅途中,Jane的肚子开始抗议了。幸运的是,Jane是一位热爱烹饪的星际旅行者,他拿出了飞船上储藏的食材,打算为自己做一顿大餐。
但是,Jane很快发现,这些食材的美味程度并不是固定的,而是与烹饪完成的时间有关。每件食材都有三个关键的属性:
a[i]:表示食材的初始美味值。
b[i]:表示食材的美味值随时间衰减的速率(即每过一秒,美味值减少b[i])。
c[i]:表示烹饪这种食材所需的时间。
Jane想要在飞船到达地球前的 T 时间内,通过合理安排食材的烹饪顺序和时间,使得最终获得的美味指数最大。然而,Jane的厨艺并不精湛,他向你这位厨艺高超的星际厨师求助,希望你能帮他解决这个问题。
输入格式
第一行是两个正整数 T 和 n,表示到达地球所需时间和食材个数。
下面一行 n 个整数,a[i];
下面一行 n 个整数,b[i];
下面一行 n 个整数,c[i]。
对于 100 的数据 1 <= n <= 50,所有数字均小于 10^5
输出格式
输出最大美味指数。
输入/输出例子1
输入:
74 1
502
2
47
输出:
408
样例解释
无
有先后关系可以尝试列式子,做差法
如果没有b[i]这个属性的话就是明显的01背包问题。
现在考虑相邻的两个物品x,y。假设现在已经耗费p的时间,那么分别列出先做x,y的代价:
a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*b[y] (①)
a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*b[x] (②)
对这两个式子化简,得到①>②的条件是c[x]*b[y]<c[y]*b[x].
发现只要满足这个条件的物品对(x,y),x在y前的代价永远更优。
因此可以根据这个条件进行排序,之后就是简单的01背包了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=55, M=1e5+5;
struct node
{
int a, b, c;
}a[N];
int t, n, f[M], ans=0;
bool cmp(node a, node b)
{
return (a.c*b.b)<(b.c*a.b);
}
signed main()
{
scanf("%lld%lld", &t, &n);
for (int i=1; i<=n; i++) scanf("%lld", &a[i].a);
for (int i=1; i<=n; i++) scanf("%lld", &a[i].b);
for (int i=1; i<=n; i++) scanf("%lld", &a[i].c);
sort(a+1, a+1+n, cmp);
for (int i=1; i<=n; i++)
for (int j=t; j>=a[i].c; j--)
f[j]=max(f[j], f[j-a[i].c]+a[i].a-j*a[i].b);
for (int i=0; i<=t; i++) ans=max(ans, f[i]);
printf("%lld", ans);
return 0;
}

浙公网安备 33010602011771号