洛谷传送门:https://www.luogu.org/problemnew/show/P1417
题意简述:总时间T,有n种食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间。问在T时间内最大美味指数为多少?
乍一看题目,很容易联想到0-1背包,仔细看此题的权值是不固定的,所以选取次序的不同会导致最大权值的不同。
所以我们在进行0-1背包选择前要先对n种食材进行排序。排序无非就是加一个排序规则。
以下是排序规则的推导:
假设有两种食材X、Y。
我们需要权值大的在前面,所以先选X再选Y的权值是要大于先选Y再选X的权值的。
将其转化成数学表达式
a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*by
>
a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*bx
化简可以得到
当X>Y时,c[x]*b[y]<c[y]*b[x]。
可以依此写出排序规则。
排好序后可以直接写一个0-1背包的模板
『代码』
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int Max = 100010;
ll t,n;
ll dp[Max] = {0};
struct Node{
int a,b,c;
}node[Max];
//排序规则
bool cmp(const Node &a,const Node &b){
return a.c*b.b < b.c*a.b;
}
int main()
{
cin>>t>>n;
for(ll i = 1 ; i <= n; i++) cin>>node[i].a;
for(ll i = 1 ; i <= n; i++) cin>>node[i].b;
for(ll i = 1 ; i <= n; i++) cin>>node[i].c;
sort(node+1,node+n+1,cmp);
for(ll i = 1 ; i <= n; i++){
for(ll j = t; j >= node[i].c; j--){
dp[j] = max(dp[j],dp[j-node[i].c] + node[i].a-j*node[i].b);
}
}
ll maxx = -1;
for(ll i = 0 ; i <= t; i++){
maxx = max(maxx,dp[i]);
//cout<<dp[i]<<" ";
}
cout<<maxx;
return 0;
}