zoukankan      html  css  js  c++  java
  • [洛谷P1417] 烹调方案

    洛谷题目链接:烹调方案

    题目背景

    由于你的帮助,火星只遭受了最小的损失。但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星。不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~

    gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子。gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了。

    题目描述

    一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间。

    众所周知,gw的厨艺不怎么样,所以他需要你设计烹调方案使得美味指数最大

    输入输出格式

    输入格式:

    第一行是两个正整数T和n,表示到达地球所需时间和食材个数。

    下面一行n个整数,ai

    下面一行n个整数,bi

    下面一行n个整数,ci

    输出格式:

    输出最大美味指数

    输入输出样例

    输入样例#1:

    74 1
    502
    2
    47

    输出样例#1:

    408

    说明

    【数据范围】

    对于40%的数据1<=n<=10

    对于100%的数据1<=n<=50

    所有数字均小于100,000

    【题目来源】

    tinylic改编


    一句话题意: (n)个物品,(T)个时刻,每个物品只能制作一次,制作需要(c_i)的时间,在(t)时刻完成第(i)样物品可以得到(a_i-t*b_i)的价值,问在(T)的时间内最多能得到多少价值.

    一眼看来显然是一个裸的01背包,然而这样是不对的...

    那么为什么这样不对呢?我们想一下,如果直接按01背包的取法,在枚举的时候物品是按顺序枚举的.但是显然先枚举到一个物品,就无法计算该物品在它之后的物品取的价值了.比如有两个物品(i,j).先取(i)物品,那么就不能算先取(j)再取(i)的价值了(想一下为什么).

    所以如果想要直接按01背包取物品的话,就要保证先取的排在前面枚举的物品能得到最大的价值.

    因为(b_i)会让取一个物品的价值不断减小,所以很容易想到一个错误的贪心:按照(b_i)排序.然而是错误的,因为这样排序出的结果也有可能不满足条件.

    所以我们考虑来如何选最优方案.假设在(t)时刻要作选择(i,j)两个物品中哪个先取,那么它们得到的价值分别是:

    [a_i-b_i*(c_i+t)+a_j-b_j*(c_i+c_j+t)$$ 和 $$a_j-b_j*(c_j+t)+a_i-b_i*(c_i+c_j+t) ]

    如果先取(i)物品得到更高的总价值,则有: $$a_i-b_i(c_i+t)+a_j-b_j(c_i+c_j+t)>a_j-b_j(c_j+t)+a_i-b_i(c_i+c_j+t)$$
    化简得到:

    [b_j*c_i < b_i*c_j ]

    这样就得到了对物品排序的方法.

    所以最后先按这个排序,再做一遍01背包就可以了.
    最后记得开long long!!!

    #include<bits/stdc++.h>
    using namespace std;
    const int N=50+5;
    const int MAXN=100000+5;
    typedef long long lol;
    
    lol T, n, f[MAXN], ans = 0;
    
    struct meal{
        lol a, b, c;
    }t[N];
    
    bool cmp(meal i,meal j){
        return j.b*i.c < i.b*j.c;
    }
    
    int main(){
        //freopen("data.in","r",stdin);
        cin >> T >> n;
        for(lol i=1;i<=n;i++) cin >> t[i].a;
        for(lol i=1;i<=n;i++) cin >> t[i].b;
        for(lol i=1;i<=n;i++) cin >> t[i].c;
        sort(t+1 , t+n+1 , cmp);
        memset(f,128,sizeof(f)); f[0] = 0;
        for(lol j=1;j<=n;j++)
    	    for(lol i=T;i>=t[j].c;i--){
    	        f[i] = max(f[i-t[j].c]+t[j].a-t[j].b*i,f[i]);
    	        ans = max(ans , f[i]);
    	    }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    JAXB基本使用
    Spring MVC手札
    Oracle创建表空间和表
    oracle删除表,让整个表从数据库中彻底消失
    oracle创建用户操作
    查看运行时某个java对象占用JVM大小及通过idea查看java的内存占用情况
    如何查看java进程
    win10下查看进程,杀死进程
    js计算两个时间相差天数
    windows 端口号占用和解决方法
  • 原文地址:https://www.cnblogs.com/BCOI/p/8999396.html
Copyright © 2011-2022 走看看