洛谷 P1417烹调方案

题目大意:

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

求最大美味指数之和。

分析:

显然的0/1背包,但是,它与平常的0/1背包不同之处在于:平常的物品不会因为时间的延续而使价值贬值,也就是说,先放a、先放b是无所谓的。

但是这个题,“ai-t*bi”的判断方法,显然相同物品的不同放置顺序,都可能得到不同的答案。

所以必然要排序。

但是怎么排序?

按照ci排?但是不一定时间短的要先做,可能其它食物b太大,贬值的很厉害。

按照bi排?但是先做贬值快的,可能由于做的时间长,仍然可能造成其它剩余食物贬值总和更大。

按照(sumb-bi)*ci排?但是由于不一定做i的时候,其它的所有的食物都留下等着做,损失其实不一定有sumb-bi那么大

按照ai-(sumb-bi)*ci排?但是这其实是只考虑了第一个做谁,仍然可能不是最优子结构。

我们这样考虑:

设身处地地想一想,我们假设已经过了p时间,还剩下两个食材x,y,你会怎么办?

一定会考虑,先做x或者先做y哪个会最大收益。

先做x:

a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*b[y] —— ①

先做y:

a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*b[x] —— ②

对这两个式子化简,得到①>②的条件是c[x]*b[y]<c[y]*b[x].

所以,对于有若干个食物,道理同样如此。

我们先按这个标准排一下序,然后0/1背包即可。

提醒:如果不用滚动数组的话,虽然好理解,但是要记得,不论j>=food[i].c与否,必须要有一个f[i][j]=f[i-1][j]

这里,我定义f[i][j]为,前i个物品,最后一次做完饭是在j时刻。也可以省略第一维。

(至于为什么要排序,假设现在x优于y,如果我们先循环的是x,就代表会先做x,再做y的时候,可以从上一次做完x的时刻转移过来美味程度。

如果y在了前面循环,那么想要同时做x,y,x必须从上一次的某一个y处转移过来,那么这个时候,x一定不是第一个做的。

或者,就算是x想要第一个做,但是y已经循环过去了,不会再从x做完后的时间转移到更靠后的j,也就扔掉了正解的转移路径。)

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=55;
const int T=100000+10;
ll f[T];
int sb;
int n,t;
struct node{
    ll a,b,c;
    bool friend operator <(node a,node b)
    {
        return a.c*b.b<b.c*a.b;
    }
}foo[N];
int main()
{
    cin>>t>>n;
    for(int i=1;i<=n;i++) scanf("%lld",&foo[i].a);
    for(int i=1;i<=n;i++) scanf("%lld",&foo[i].b);
    for(int i=1;i<=n;i++) scanf("%lld",&foo[i].c);
    sort(foo+1,foo+n+1);
    for(int i=1;i<=n;i++)
     for(int j=t;j>=foo[i].c;j--)
     {
         f[j]=max(f[j],f[j-foo[i].c]+foo[i].a-foo[i].b*j);
     }
    ll ans=0;
     for(int i=1;i<=t;i++)
      ans=max(ans,f[i]);
    cout<<ans;
    return 0;
}

同理的,还有一道考试题:

再过T天就是Kate的生日了,Coffee打算送它一些蛋糕。在Coffee和Kate的世界,蛋糕是做不出来的,而是种出来了。

Coffee收藏着N个蛋糕种子。第i个蛋糕种子需要在室内培育连续Pi天才能长成幼苗,之后将它移栽到室外,再经过Qi天后就会结出一个美味度为Ri的蛋糕。移栽蛋糕苗、为室外的蛋糕浇水以及收取成熟的蛋糕花费的时间对于Coffee来说可以忽略不计,但由于长成幼苗前的蛋糕比较娇嫩,照顾起来也更麻烦,Coffee每天最多只会照顾一棵蛋糕幼苗。

更具体地,如果Coffee在第t0天开始室内培育第i个蛋糕种子,那么它的室内培育工作会占用Coffee第t0..t0+(Pi)-1,并会在t0+Pi+(Qi)-1天结出蛋糕。在t0..t0+(Pi)-1天,Coffee不会开始或同时培养其他种子。

Coffee希望在Kate生日时,送给Kate的蛋糕们的美味度总和尽量大。也就是说,在接下来的T天内,Kate最多能收获蛋糕的美味度总和最大是多少?注意,即使一个蛋糕苗在第T天前已经被移出了室外,只要它在Kate的生日前没能结出蛋糕,它的美味度就不会被计算到总美味度中。

分析:

发现Q这个延时很麻烦,处理的时候还得想之前有没有种过。可以取巧地,假设过完了P天,就立刻熟了,收获了,但是“收获”的这一天不能晚于T-Qi(这个转化就是合法的)

所以就剩一个0/1背包了。

因为对于不同的物品,有不同的背包上界,既然如此,肯定先考虑,把上界低的先放进包里,因为再高了就放不了了。

上界高的,能力大,就可以放到再靠上的包的空间里。

也就是把公共的区间让范围小的先去填充。排序即可。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=300+10;
const int T=20000+10;
int f[N][T];
struct node{
    int cost,dis,val;
}ca[N];
int n,t;
bool cmp(node a,node b)
{
    if(a.dis!=b.dis) return a.dis>b.dis;
    return a.cost<b.cost;
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
     scanf("%d%d%d",&ca[i].cost,&ca[i].dis,&ca[i].val);
    sort(ca+1,ca+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
     for(int j=t-ca[i].dis;j>=1;j--)
      {f[i][j]=f[i-1][j];
      if(j>=ca[i].cost) f[i][j]=max(f[i][j],f[i-1][j-ca[i].cost]+ca[i].val);}
     for(int j=1;j<=t;j++)
       cout<<f[i][j]<<endl;
    cout<<endl;
    }
    int ans=0;
    for(int i=1;i<=t;i++)
     ans=max(ans,f[n][i]);
    printf("%d",ans);
    return 0;
}

总结:

1.背包的变式其实是非常多的,总体的定义、循环相差不大,但是关键点多出在排序。

2.排序本质上都是两两之间的物品进行最优解的比较,所以考虑如何排序的时候,可以尝试单独考虑这两个元素之间的大小关系,从而列出式子。

3.背包不能凭感觉瞎想,一定要分析好物品循环的先后顺序。

4.背包本质上还是背包,就是往有限空间里放东西,只是东西千奇百怪罢了,但是考虑方式是可以转化到基础的放东西模型上的。

原文地址:https://www.cnblogs.com/Miracevin/p/9059258.html

时间: 2024-10-09 17:30:23

洛谷 P1417烹调方案的相关文章

洛谷P1417 烹调方案

洛谷P1417 烹调方案如果是一般的01背包的话 选的先后是没关系的但是这题选的先后是有关系的,因为他的价值是随着时间而变化的,而你的01背包是做不到先选2再选1的那么我们就跟国王游戏一样 用一个优先值对他们就行排序,表示如果初始价值相同应该怎么选,这其实就是国王游戏,然后我们用贪心原则将他们排好序,然后再来一遍01背包就行了 1 #include <bits/stdc++.h> 2 #define For(i,j,k) for(int i=j;i<=k;i++) 3 #define i

luogu P1417 烹调方案

题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子.gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了. 题目描述 一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间. 众所周知,gw

P1417 烹调方案

题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子.gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了. 题目描述 一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间. 众所周知,gw

P1417 烹调方案 背包DP

题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子.gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了. 题目描述 一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间. 众所周知,gw

P1417 烹调方案(思维+01背包)

(点击此处查看原题) 题意 有n种食材,每种食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去ci的时间.问在T时间内,什么样的烹调方案使得美味指数最大,输出最大的美味指数 解题思路 简单看来,这就是一个01背包问题,但是不同之处在于这里每个食材的价值会因为时间而改变,所以对于每个时间点,我们需要考虑此时先选择哪一种食材 记now为当前时间,食材1的属性:a1,b1,c1,食材2的属性:a2,b2,c2 1)先选择食材1的总价值:a

[NOIP2006] 提高组 洛谷P1065 作业调度方案

题目描述 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的每道工序都有指定的加工时间. 每个工件的每个工序称为一个操作,我们用记号j-k表示一个操作,其中j为1到n中的某个数字,为工件号:k为1到m中的某个数字,为工序号,例如2-4表示第2个工件第4道工序的这个操作.在本题中,我们还给定对于各操作的一个安排顺序. 例如,当n=3,m=2时,“1-1,1-2,2-1,3-1,3-2,2-2”就是一个给定的安排顺序,即先安排第1个工件的第1个工

洛谷——背包型dp

1.P1417 烹调方案 题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的食物准备填饱肚子.gw希望能在T时间内做出最美味的食物,但是这些食物美味程度的计算方式比较奇葩,于是绝望的gw只好求助于你了. 题目描述 一共有n件食材,每件食材有三个属性,ai,bi和ci,如果在t时刻完成第i样食材则得到ai-t*bi的美味指数,用第i件食材做饭要花去c

洛谷P1108 低价购买[DP | LIS方案数]

题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它.买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数.你将被给出一段时间内一支股票每天的出售价(2^16范围内的正整数),你可以选择在哪些天购买这支股票.每次购买都必须遵循“低价购买:再低价购买”的原则.写一个程序计算最大购买次数. 这里是某支股票的价格清单: 日期 1 2

洛谷教主花园dp

洛谷-教主的花园-动态规划 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的