题目大意:

一共有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=;
const int T=+;
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=;i<=n;i++) scanf("%lld",&foo[i].a);
for(int i=;i<=n;i++) scanf("%lld",&foo[i].b);
for(int i=;i<=n;i++) scanf("%lld",&foo[i].c);
sort(foo+,foo+n+);
for(int i=;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=;
for(int i=;i<=t;i++)
ans=max(ans,f[i]);
cout<<ans;
return ;
}

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

再过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=+;
const int T=+;
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=;i<=n;i++)
scanf("%d%d%d",&ca[i].cost,&ca[i].dis,&ca[i].val);
sort(ca+,ca+n+,cmp);
for(int i=;i<=n;i++)
{
for(int j=t-ca[i].dis;j>=;j--)
{f[i][j]=f[i-][j];
if(j>=ca[i].cost) f[i][j]=max(f[i][j],f[i-][j-ca[i].cost]+ca[i].val);}
for(int j=;j<=t;j++)
cout<<f[i][j]<<endl;
cout<<endl;
}
int ans=;
for(int i=;i<=t;i++)
ans=max(ans,f[n][i]);
printf("%d",ans);
return ;
}

总结:

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

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

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

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

5.背包物品的循环顺序,本质上就是考虑放物品的先后顺序。不会存在先考虑,却在实际操作中是后放进去的。

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

  1. [洛谷P1417 烹调方案]贪心+dp

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3211Dream City Time Limit: 1 Second     ...

  2. 洛谷P1417 烹调方案

    题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的 ...

  3. 洛谷 P1417 烹调方案

    题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的 ...

  4. 洛谷P1417 烹调方案【dp】

    题目:https://www.luogu.org/problemnew/show/P1417 题意: 一道菜有$a,b,c$三个值.烧一道菜的时间是$c$.得到的价值是,$a-t*b$其中$t$是菜完 ...

  5. 洛谷 P1417 烹调方案 (01背包拓展)

    一看到这道题就是01背包 但是我注意到价值和当前的时间有关. 没有想太多,直接写,0分 然后发现输入方式不对-- 改了之后只有25分 我知道wa是因为时间会影响价值,但不知道怎么做. 后来看了题解,发 ...

  6. 洛谷 P1417 烹调方案 题解

    题面 这道题是一道典型的排序dp 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 ...

  7. 洛谷1417 烹调方案 dp 贪心

    洛谷 1417 dp 传送门 挺有趣的一道dp题目,看上去接近于0/1背包,但是考虑到取每个点时间不同会对最后结果产生影响,因此需要进行预处理 对于物品x和物品y,当时间为p时,先加x后加y的收益为 ...

  8. 【洛谷】【动态规划/背包】P1417 烹调方案

    由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船飞到一半,gw发现了一个很严重的问题:肚子饿了~ gw还是会做饭的,于是拿出了储藏的食物准备填 ...

  9. P1417 烹调方案

    P1417 烹调方案 题目提供者tinylic 标签 动态规划 难度 普及+/提高 题目背景 由于你的帮助,火星只遭受了最小的损失.但gw懒得重建家园了,就造了一艘飞船飞向遥远的earth星.不过飞船 ...

随机推荐

  1. 关于Prometheus运维实践项目

    关于Promethues运维实践项目 1. 什么是Prometheus运维实践项目 ​ 是什么 ​ Prometheus,普罗米修斯,是古希腊神话中为人间带来火种的神. ​ Prometheus运维实 ...

  2. Nagios监控系统部署(源码)

    1. 概述2. 部署Nagios2.1 创建Nagios用户组2.2 下载Nagios和Nagios-plugin源码2.3 编译安装3. 部署Nagios-plugin3.1 编译安装nagios- ...

  3. Linux下DNS简单部署(主从域名服务器)

    一.DNS简介DNS(Domain Name System),域名系统,因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串.通 ...

  4. Keepalived基础知识-运维小结

    keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...

  5. Chrome F12调试

    F12 断点 F5 Esc 选择鼠标右击:编辑||hover样式 Sonrces go to file (ctrl+p) 搜搜文件名

  6. [BUAA软工]第一次结对作业

    [BUAA软工]结对作业 本次作业所属课程: 2019BUAA软件工程 本次作业要求: 结对项目 我在本课程的目标: 熟悉结对合作,为团队合作打下基础 本次作业的帮助:理解一个c++ 项目的开发历程 ...

  7. android计算器

    一:引言    目前手机可以说是普及率非常高的电子设备了,由于其便于携带,使用方便,资费适中等等原因,现在手机已经在一定程度开始代替固定电话的通话功能,以及一些原来电脑软件上的功能了.手机上的软件也随 ...

  8. vuejs基础

    **### 数据与方法 // 我们的数据对象 var data = { a: 1 } // 该对象被加入到一个 Vue 实例中 var vm = new Vue({ data: data }) // ...

  9. b总结

    Beta 答辩总结 评审表 组名 格式 内容 ppt 演讲 答辩 总计 天机组 15 15 13 15 14 72 PMS 16 16 15 16 16 79 日不落战队 16 17 17 17 17 ...

  10. HDU 2029 Palindromes _easy version

    http://acm.hdu.edu.cn/showproblem.php?pid=2029 Problem Description “回文串”是一个正读和反读都一样的字符串,比如“level”或者“ ...