首页 > 技术文章 > 洛谷 OJ P1417 烹调方案 01背包

lighter-blog 2017-08-17 17:02 原文

题目背景

由于你的帮助,火星只遭受了最小的损失。但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

 

01背包的思路,不过物品的价值会随着时间改变,因此要先排序。

假设现在的时间是 0,有两个物品,他们的参数分别为  ai,bi,ci 和 aj,bj,cj。

如果先放第一个物品再放第二个物品,则价值为 ai - bi*ci + aj - bj*(ci + cj)

如果先放第二个物品再放第一个物品,则价值为 aj - bj*cj + ai - bi*(cj + ci)

假设第一种方法要比第二种方法更优,则得到不等式 ai - bi*ci + aj - bj*(ci + cj) > aj - bj*cj + ai - bi*(cj + ci)

将其化简后,可以得到式子  bj * ci < bi * cj

也就是说,如果满足上面的式子,则先放第一个物品,再放第二个物品这种方法一定是最优的。

因此将所有物品按照上面的方法进行排序后,再进行01背包,得到的结果就会使最优解。

 

代码:

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

const int MAX = 100005; 

struct Node{
    long long a, b, c;
};

long long dp[MAX];
Node node[MAX];
int t, n;

bool cmp(Node a, Node b){        
    return b.b * a.c < a.b * b.c;
}

int main(){
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    
    cin >> t >> n;
    for(int i=1; i<=n; i++){
        cin >> node[i].a;
    }
    for(int i=1; i<=n; i++){
        cin >> node[i].b;
    }
    for(int i=1; i<=n; i++){
        cin >> node[i].c;
    }
    
    //按照优先级进行排序 
    sort(node+1, node+1+n, cmp);
    
    //DP  01背包 
    memset(dp, 0, sizeof(dp));
    for(long long i=1; i<=n; i++){
        long long a = node[i].a;
        long long b = node[i].b;
        long long c = node[i].c;
        for(long long j=t; j>=c; j--){
            dp[j] = max(dp[j], dp[j-c] + a - b*j);
        }
    }
    
    long long ans = 0;
    
    for(int i=0; i<=t; i++){
        ans = max(ans, dp[i]);
    }
    
    cout << ans;
    
    return 0;
}

 

推荐阅读