贪心 + DP(01背包):烹调方案

这篇博客分析了一个不能直接应用普通01背包算法的题目,原因是选取顺序对结果有影响。博主提出了一种贪心策略,通过比较物品在不同选取顺序下的价值变化来排序物品,并给出了状态转移方程和代码实现。最终,通过贪心排序后的01背包解决了问题。

题目链接:https://www.luogu.com.cn/problem/P1417

分析:

1.此题目为什么不能用普通的01背包呢?因为01背包的要求是不同顺序的选取对结果不会造成影响,而此题不是,此题相同的总选取物品在不同选取顺序下,得到的答案是不同的。(也可以看成,价值在不断的改变,虽然物品没变,但是在不同的时间取,对应的价值不同,实际上就可以看成是不同的物品。所以不能用普通的01背包)。

2.还需要加上贪心的思路:

列一下公式,两个物品哪种取值是最优的呢?,i,j两个物品

i先取然后取j:a[i]−b[i]∗(t+c[i])+a[j]−b[j]∗(t+c[i]+c[j])

j先取然后取i: a[j]−b[j]∗(t+c[j])+a[i]−b[i]∗(t+c[i]+c[j])

当a[i]−b[i]∗(t+c[i])+a[j]−b[j]∗(t+c[i]+c[j]) >= a[j]−b[j]∗(t+c[j])+a[i]−b[i]∗(t+c[i]+c[j])时,i先取更优。

进行化简,消元

--------》 −b[i]∗(t+c[i])−b[j]∗(t+c[i]+c[j]) >= −b[j]∗(t+c[j])−b[i]∗(t+c[i]+c[j])

--------》−b[j]∗c[i]>−b[i]∗c[j]

所以两个物品按照此方式进行排序即可。当−b[j]∗c[i]>−b[i]∗c[j], i放前面,先选择i.

这样就可以使用01背包了。

状态表示:

f[i][j] : 前i个物品,i完成时,到达j分钟 获得的最大价值

代码实现:

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

const int N = 60 , M = 100010;

long long f[2][M];

int t,n;

struct Node
{
    long long a,b,c;
}tr[N];

bool cmp(struct Node t1 , struct Node t2)
{
    return -t2.b * t1.c > -t1.b * t2.c;
}

int main()
{
    scanf("%d %d",&t,&n);
    for(int i = 1 ; i <= n ;i++)
    {
        scanf("%lld",&tr[i].a);
    }
    for(int i = 1 ; i <= n ; i++)
    {
        scanf("%lld",&tr[i].b);
    }
    for(int i = 1 ; i <= n ; i++)
    {
        scanf("%lld",&tr[i].c);
    }

    sort(tr + 1 , tr + 1 + n , cmp);

    long long ans = -0x3f3f3f3f;

    for(int i = 1 ; i <= n ; i++)
    {
        for(int j = t ; j >= 0 ; j--)
        {
            f[i % 2][j] = f[ (i - 1) % 2][j];
            if(tr[i].c <= j)
            {
                f[i % 2][j] = max(f[i % 2][j],f[ (i - 1) % 2][j - tr[i].c ] + tr[i].a - j * tr[i].b);
            }
        }
    }
    for(int i = 0 ; i <= t ; i++)
    {
        ans = max(ans,f[n % 2][i]);
    }
    printf("%lld\n",ans);
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值