题目描述

小明是个大厨,早上起来他开始一天的工作。他所在的餐厅每天早上都会买好n件食材(每种食材的数量可以视为无限),小明从到达餐厅开始就连续工作T时间。每道菜肴的制作需要特定的一种食材以及一段时间,但是食材一旦放久就不新鲜了,菜的美味值会降低。第i道菜肴有三个属性ai,bi,ci,ai是该菜肴的美味值,bi是该菜肴所选食材不新鲜的速率,如果在第t时刻完成第i道菜则美味值为:ai-t*bi,完成这道菜需要ci的时间。小明希望在这T时间内能做出菜肴使得总美味值最大,所以小明求助于你。

输入描述:

第1行输入三个整数n,m,T,分别代表食材种类,菜肴种类和工作时间。
第2行输入n个整数bi,代表第i个食材不新鲜的速率。
第3-n+2行,每行输入三个整数j,ai,ci,分别代表第i道菜肴需要的食材编号,菜肴的美味值,完成时间。
数据保证:0<n,m≤50,0<j≤n,其他值均<106,美味值必须通过完整做出菜肴得到,数据保证在规定时间内至少能完整做出1道菜肴。

输出描述:

输出一行,一个整数,表示最大总美味值。

题解

背包+贪心
上来就背包肯定是错的, 因为这里多了一个时间的限制, 价值随着时间而变化。因此需要考虑贪心策略下背包。对于物品进入放入背包的时间顺序,必然是用时越短的物品越先放进去的策略最优。所以我们排个序之后再去跑背包就行了QAQ

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct node{
    int a,b,c;
    bool operator < (const node &rhs)const{
        return rhs.c*b>rhs.b*c;
    }
}s[55];
long long dp[N];
int b[55];
int main(){
    int n,m,T;
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=n;++i){
        scanf("%d",&b[i]);
    }
    for(int i=1;i<=m;++i){
        int id;
        scanf("%d%d%d",&id,&s[i].a,&s[i].c);
        s[i].b=b[id];
    }
    sort(s+1,s+1+m);
    memset(dp,-0x3f,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=m;++i){
        for(int j=T;j>=s[i].c;--j){
            dp[j]=max(dp[j],dp[j-s[i].c]+s[i].a-j*s[i].b);
        }
    }
    sort(dp+1,dp+T+1);
    cout<<dp[T]<<endl;
}