P1417 烹调方案 题解&贪心杂谈

这篇具有很好参考价值的文章主要介绍了P1417 烹调方案 题解&贪心杂谈。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • Description
  • Solution
  • Code

Description

一共有 \(n\) 个食物,每个食物有3个属性,分别为 \(a,b,c\),其中 \(c\) 表示做这道菜的耗时。

一个食物的贡献为 \(a-b\times t\),其中 \(t\) 表示做完这道菜的总耗时,求在 \(T\) 个单位时间内,最多能产生多少贡献。

Solution

首先,通过 \(T\) 的限制,\(a-b\times t\) 的贡献可以看出这是一道背包问题。

我们考虑 \(f_{i,j}\) 表示前 \(i\) 个食物耗时 \(j\) 的时间所得贡献的最大值,而裸的背包是不用排序的,所以考虑直接DP。

很快就能发现,这个做法假掉了,因为遍历到 \(y\) 的时候选了 \(x,y\),而到 \(z\) 的时候,最佳方案却为 \(y,z\),具有后效性。举个例子:

  • \(a_1=15,a_2=16,a_3=15\)
  • \(b_1=2,b_2=3,b_3=2\)
  • \(c_1=4 ,c_2=3,c_3=3\)

在7个单位时间内,若按输入顺序遍历,得到的最大贡献为8(先做第一道菜,再做第三道),而实际上,最大贡献为10(先做第二道菜,再做第三道菜)。

所以我们尝试用贪心寻找一个正确的排序方案。

我们发现,这道题和一道小学奥数题有些类似,即排队打饭或排队接水问题:

\(n\) 个人,每个人耗费 \(a_i\) 秒打饭,请问应怎么排序,能使每个人的排队时间总和最短。

这道题很简单,按照打饭时间从小到大排序即可。

回到本题,我们是否也能按 \(c_i\) 从小到大排序呢。

答案是不行。

因为一个食物的贡献只中 \(b_i\) 也是和排序顺序相关的,只有 \(a_i\) 是与排序无关的。

所以我们考虑列出式子,找到真正的排序方案。

钦定 \(i,j\) 的排序是优于 \(j,i\) 的,那么:

\(a_i-b_i\times(t+c_i)+a_j-b_j\times(t+c_i+c_j)> a_j-b_j\times(t+c_j)+a_i-b_i\times(t+c_j+c_i)\)

拆开括号,化简得:\(b_j\times c_i<b_i\times c_j\)

到这里,我们的比较器已经出来了,很多同学到这里就会直接开始码字,然后发现是正确的,但为什么这是正确的呢。

正确性证明在许多题解中都是一笔略过的,但有大神说过,一道题如果没有严谨的正确性证明,那么这道题的价值就几乎没有,这句话是有理的。

我们上面的证明只证明了 \(i,j\) 在这个比较器下是优于 \(j,i\) 的,但没有证明当 \(i,j\) 更优,\(j,k\) 更优时,\(i,k\) 也是更优的,也就是说,只有一个比较器能在有限次数内将一个无序的数列转化为最有的排列,才能证明这个比较器是正确的。

将上述转为数学式子:

已知 \(\begin{cases} b_j\times c_i<b_i\times c_j\\b_k\times c_j<b_j\times c_k\end{cases}\)

求证 \(b_k\times c_i<b_i\times c_k\)

证明如下:

由一式与二式可得 \(b_j\times c_i+b_k\times c_j<b_i\times c_j+b_j\times c_k\)

\(\therefore b_j\times(c_i-c_k)<c_j\times(b_i-b_k)\)

\(\therefore\dfrac{b_j}{c_j}<\dfrac{b_i-b_k}{c_i-c_k}\)

将二式转换可得 \(\dfrac{b_k}{c_k}<\dfrac{b_j}{c_j}\)

\(\therefore \dfrac{b_k}{c_k}<\dfrac{b_i-b_k}{c_i-c_k}\)

\(\therefore b_k\times(c_i-c_k)<c_k\times(b_i-b_k)\)

拆开后合并同类项,\(b_k\times(c_i+c_k)<c_k\times(b_i+b_k)\)

\(\therefore \dfrac{c_i+c_k}{c_k}<\dfrac{b_i+b_k}{b_k}\)

\(\therefore \dfrac{c_i}{c_k}+1<\dfrac{b_i}{b_k}+1\)

\(\therefore b_k\times c_i<b_i\times c_k\)

证毕。

比较器证明完后,我们回到DP上,发现DP的转移顺序也十分重要。

在转移 \(t\) 时,我们要从大到小地遍历。

因为 \(t\) 较大的方案是通过 \(t\) 较小的方案转移而得,所以如果从小到大遍历,\(t\) 较小的方案可能会被更新,导致 \(t\) 较大的方案出现错误。

Code

#include<bits/stdc++.h>
using namespace std;
int t,n;
long long dp[100010];  //注意数据范围,要开long long
struct food{
	long long a,b,c;
}s[100];
bool cmp(food x,food y){
	return x.c*(-y.b)>y.c*(-x.b);
}
int main(){
	cin>>t>>n;
	for(int i=1;i<=n;i++){
		cin>>s[i].a;
	}
	for(int i=1;i<=n;i++){
		cin>>s[i].b;
	}
	for(int i=1;i<=n;i++){
		cin>>s[i].c;
	}
	sort(s+1,s+1+n,cmp); 
	for(int i=1;i<=n;i++){
		for(int j=t;j>=s[i].c;j--){  //注意遍历顺序
			dp[j]=max(dp[j],dp[j-s[i].c]+s[i].a-j*s[i].b);
		}
	}
	long long ans=0;
	for(int i=1;i<=t;i++){
		ans=max(ans,dp[i]);
	}
	cout<<ans<<endl;
}

绝大多数时候,贪心都是口胡而得,并无严谨证明,而很多时候贪心也是因此假掉的。虽然贪心很重要,但更重要的是掌握它的正确性证明,以及如何在考场上快速得出正确贪心的策略。文章来源地址https://www.toymoban.com/news/detail-710276.html

到了这里,关于P1417 烹调方案 题解&贪心杂谈的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【洛谷 P1003】[NOIP2011 提高组] 铺地毯 题解(数组+贪心算法)

    为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 n n n 张地毯,编号从 1 1 1 到 n n n 。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上

    2023年04月24日
    浏览(48)
  • python - leetcode - 424. 替换后的最长重复字符【经典题解 - 贪心滑动窗口算法】

    描述: 给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后,返回包含相同字母的最长子字符串的长度。 示例 1: 示例 2: 提示: 1 = s.length = 105 s 仅由大写英文字母组成 0 =

    2024年02月16日
    浏览(46)
  • 【杂谈】“CommunityToolkit.Mvvm无法自动生成Get/Set属性对”的解决方案

    最近在实践MVVM,发现这玩意儿挺有意思的,有点WPF的最佳搭档的感觉。UI自动跟随VM变化,极大程度上简化各类逻辑。UI元素的各种属性也会实时反馈到VM上,直接在VM处理事务逻辑即可。 但是MVVM在WPF上应用,最烦的就是要自己写一大堆Get/Set,以及匹配 INotifyPropertyChanged 的调

    2024年02月08日
    浏览(41)
  • 信息学奥赛一本通(基础算法与数据结构-题解汇总目录)

    信息学奥赛一本通(C++版)在线评测系统 基础(二)基础算法   更新中。。。。。。 第一章高精度计算 1307【例1.3】高精度乘法 1308【例1.5】高精除 1309【例1.6】回文数(Noip1999) 1168大整数加法 1169大整数减法 1170计算2的N次方 1171大整数的因子 1172求10000以内n的阶乘 1173阶乘

    2024年02月16日
    浏览(46)
  • java实现0-1背包问题方案(动态规划-贪心算法-回溯-分支定界)

    动态规划算法时间复杂度较低,能够求解较大规模的问题,但空间复杂度较高,不适用于数据量较大的问题。 贪心算法时间复杂度较低,能够求解较大规模的问题,但不能保证求得的解是最优解。 回溯算法能够求解较小规模的问题,但时间复杂度较高,不适用于数据量较大

    2024年02月01日
    浏览(122)
  • 目录遍历漏洞原理、解决方案

    目录遍历(路径遍历)是由于web服务器或者web应用程序对用户输入的文件名称的安全性验证不足而导致的一种安全漏洞,使得攻击者通过利用一些特殊字符就可以绕过服务器的安全限制,访问任意的文件(可以使web根目录以外的文件),甚至执行系统命令。 存在的危害 读取

    2024年02月02日
    浏览(42)
  • Docker数据目录迁移解决方案

    使用以下命令查询当前docker数据目录安装路径: 下文以 /home/rain/docker 这个路径作为要迁移的新 Docker 安装(存储)目录 方法一:软链接 停掉Docker服务: 根据上面查到的路径,移动整个 /var/lib/docker 目录到数据盘的目的路径(没有rsync命令时需安装rsync): 参数解释: -a,归档模式

    2024年02月07日
    浏览(51)
  • Linux设置临时目录路径的解决方案

      大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作

    2024年02月10日
    浏览(42)
  • 关于“Loading PDSC Debug Description Failed”

    关于这个问题的弹窗报错网上也已经有了清晰的解决思路,就是更改软件目录下对应的.pdsc文件(譬如*/ARM/PACK/Keil/STM32F4XXXXXX/2.15.0/ Keil.STM32F4xx_DFP.pdsc )去掉该文件的只读属性,并根据Keil底部的build output内的提示找到对应行,删除该行的报错提示,保存文件。 Message(2, \\\"Not a

    2024年02月06日
    浏览(42)
  • ERROR:cannot load flash device description

    前言 :在移植他人 代码时,用keil5下载程序时有时会出现 cannot load flash device description的 问题,以下是解决方法: 此处,我是因为原本使用的是J-Link,改为ST-Link后,发生了报错。 通常,很多时候都是因为没有找到对应得flash 下载算法导致, 要选择正确的Flash Download 程序,型

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包