(luogu1417)烹调方案

原题链接

思路:

乍一看像一个普通的01背包, 但是每个物品的”价值”是与时间有关的, 所以不是个单纯的01背包.

同时考虑物品的顺序对结果有影响, 所以不能只用dp解决.

考虑物品$i$与物品$j$, 假设已经花费时间$t$, 则先取$i$后取$j$增加的价值为:

先取$j$后取$i$为:

若$v_1 > v_2$, 则有:

也即, 对于两个物品的序偶$< i, j >$, 如果满足上述不等式, 则优先考虑$i$更优.

所以对物品按上述方式排序后, 按此排序进行dp就解决了物品考虑顺序的问题(按此顺序比其他顺序一定更优), 剩下的就是01背包了.

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
#include <algorithm>
using std::sort;
using std::max;
typedef long long LL;
const int Mn(55),Mt(100500);

struct Food {
LL a,b,c;
bool operator < (const Food& rhs) const {
return rhs.c*b>rhs.b*c; //排序方式
}
}arr[Mn];

LL dp[Mt];

int main() {
int t,n;
scanf("%d %d",&t,&n);
for(int i(1);i<=n;++i) {
scanf("%lld",&arr[i].a);
}
for(int i(1);i<=n;++i) {
scanf("%lld",&arr[i].b);
}
for(int i(1);i<=n;++i) {
scanf("%lld",&arr[i].c);
}
sort(arr+1,arr+n+1); //排序
//01背包
for(int i(1);i<=n;++i) {
Food& x(arr[i]);
for(int j(t);j>=x.c;--j) {
dp[j] = max(dp[j],dp[j-x.c]+x.a-1ll*j*x.b);
}
}
//寻找答案
LL ans(0);
for(int i(0);i<=t;++i) {
ans = max(ans,dp[i]);
}
printf("%lld",ans);
return 0;
}