luogu1417 烹调方案

题目大意

  一共有$n$件食材,每件食材有三个属性,$a_i$,$b_i$和$c_i$,如果在$t$时刻完成第$i$样食材则得到$a_i-t*b_i$的美味指数,用第$i$件食材做饭要花去$c_i$的时间。请设计烹调方案使得美味指数最大。

题解

  这是一道典型的通过邻项交换进行贪心,随后得到动规方向的例子。如果没有$b_i$,这就是一个简单的01背包;有了$b_i$,我们可以尝试给物品排个序。

  对于相邻的两个元素$i,j$,它们在$t$时刻开始做,它们不交换时,美味度和为$$a_i -b_i t+a_j -b_j(t+c_i)\tag 1$$,交换后,美味度和为$$a_j-b_j t+a_i -b_i(t+c_j)\tag 2$$。若要使正常的顺序使它们的和最大,则$$(1)-(2)=b_i c_j -b_j c_i>0$$。所以按照此排序后再01背包即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX_OBJ = 60, MAX_V = 100010, MINF = 0xcfcfcfcf;

struct Node
{
    long long A, B, C;

    bool operator < (const Node& a) const
    {
        return a.B * C < B * a.C;
    }
}_objs[MAX_OBJ];

int TotObj, TotV;

long long DP()
{
    static long long F[MAX_V];
    memset(F, 0xcf, sizeof(F));
    F[0] = 0;
    for (int i = 1; i <= TotObj; i++)
        for (int j = TotV; j >= _objs[i].C; j--)
            F[j] = max(F[j], F[j - _objs[i].C] + _objs[i].A - _objs[i].B * j);
    long long ans = 0;
    for (int i = 1; i <= TotV; i++)
        ans = max(ans, F[i]);
    return ans;
}

int main()
{
    scanf("%d%d", &TotV, &TotObj);
    for (int i = 1; i <= TotObj; i++)
        scanf("%lld", &_objs[i].A);
    for (int i = 1; i <= TotObj; i++)
        scanf("%lld", &_objs[i].B);
    for (int i = 1; i <= TotObj; i++)
        scanf("%lld", &_objs[i].C);
    sort(_objs + 1, _objs + TotObj + 1);
    printf("%lld\n", DP());
    return 0;
}

  

posted @ 2018-08-15 10:01  headboy2002  阅读(94)  评论(0编辑  收藏  举报