首页 > 其他分享 >贪心总结

贪心总结

时间:2024-12-23 19:30:19浏览次数:7  
标签:总结 le min max 大臣 区间 排序 贪心

每次都选当下的最优解,一步步得到全局的最优。

可以贪心的题目的性质

  • 最优子结构性质:选择当前问题的最优决策不会影响子问题的最优决策。

  • 贪心选择性:当前决策依赖于已经做出的决策,且决策一旦做出边不能更改。

证明贪心策略正确的方法

  1. 反证法:如果交换某两个元素后不会得到更好的答案,那么当前答案就是最优的。

  2. 归纳法:先算出边界的最优解,再证明下一步的最优解可以通过这一步的最优解得到。

寻找贪心策略的方法

  • 直觉+归纳法。

  • 领项交换法。

实现

普通贪心

后悔贪心

都有一种共性:将文字转化为数学关系进行推导。

经典的模型与方法

邻项交换法

在可以通过比较相邻两项得出交换或不交换一定不会更差时,可以用邻项交换法得到最优解。

注意邻项交换法得到的排序函数要满足严格弱序,并且排序完成后任意交换相邻元素都不会更优。这样才能保证算法正确。这一点详见拓展。

普通的邻项交换法例子

luogu国王游戏

恰逢 H 国国庆,国王邀请 \(n\) 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 \(n\) 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

Sol:

设排序后第\(i\)个大臣左手右手上的数分别为\(a_i,b_i\),第\(i\)个大臣前面所有人左手上的数乘积为\(s\)。

那么第\(i\)个大臣获得的奖赏为\(\frac{s}{b_i}\),第\(i+1\)个大臣获得的奖赏为\(\frac{s\cdot a_i}{b_{i+1}}\)。

若交换第\(i\)、\(i+1\)个大臣,那么原来的第\(i\)个大臣获得的奖赏为\(\frac{s\cdot a_{i+1}}{b_i}\),原来的第\(i+1\)个大臣获得的奖赏为\(\frac{s}{b_{i+1}}\)。

交换前更优当且仅当:\(\max(\frac{s}{b_i},\frac{s\cdot a_i}{b_{i+1}})<\max(\frac{s\cdot a_{i+1}}{b_i},\frac{s}{b_{i+1}})\)

都约去\(s\),并乘上\(b_ib_{i+1}\)得\(\max(b_{i+1},a_ib_i)<\max(a_{i+1}b_{i+1},b_i)\)

这个已经可以做了,但还可以注意到\(a_ib_i>b_i,b_{i+1}<a_{i+1}b_{i+1}\),那么不等式等价于\(a_ib_i<a_{i+1}b_{i+1}\),排序即可。

拓展

luogu皇后游戏

一道推式子以及更严谨地考虑贪心策略的好题。

皇后有 \(n\) 位大臣,每位大臣的左右手上面分别写上了一个正整数。恰逢国庆节来临,皇后决定为 \(n\) 位大臣颁发奖金,其中第 \(i\) 位大臣所获得的奖金数目为第 \(i - 1\) 位大臣所获得奖金数目与前 \(i\) 位大臣左手上的数的和的较大值再加上第 \(i\) 位大臣右手上的数。

形式化地讲:我们设第 \(i\) 位大臣左手上的正整数为 \(a_i\),右手上的正整数为 \(b_i\),则第 \(i\) 位大臣获得的奖金数目为 \(c_i\) 可以表达为:

\[c_{i} = \begin{cases} a_{1}+b_{1} & ,i=1 \\ \displaystyle \max \left \{ c_{i-1},\sum_{j=1}^{i}a_{j} \right \} +b_{i} & ,2\leq i \leq n \end{cases} \]

当然,吝啬的皇后并不希望太多的奖金被发给大臣,所以她想请你来重新安排一下队伍的顺序,使得获得奖金最多的大臣,所获奖金数目尽可能的少

注意:重新安排队伍并不意味着一定要打乱顺序,我们允许不改变任何一位大臣的位置。

Sol:

显然地,获得奖金最多的大臣是排在最后的那一个。

考虑相邻的两个大臣\(i,j\),其中\(j=i+1\)。交换\(i,j\)对前面的大臣没有影响,对后面的大臣影响在于\(j\)获得的奖金,要使之尽量小。

设这两个大臣之前所有大臣左手上的数字之和为\(s\),这两个大臣的前面那个大臣获得的奖金为\(p\)。

  • 当\(i\)排在\(j\)前面时,二者中靠后那人获得的奖金为\(\max(\max(p,s+a_i)+b_i,s+a_i+a_j)+b_j\),记为\(1\)式。

  • 当\(j\)排在\(i\)前面时,二者中靠后那人获得的奖金为\(\max(\max(p,s+a_j)+b_j,s+a_i+a_j)+b_i\),记为\(2\)式。

根据加法对\(\max\)的分配律,可以对两个式子化简。

\(1\)式:\(\max(p+b_i+b_j,s+a_i+b_i+b_j,s+a_i+a_j+b_j)\)

\(2\)式:\(\max(p+b_i+b_j,s+a_j+b_i+b_j,s+a_i+a_j+b_i)\)

设\(A=p+b_i+b_j,B=\max(s+a_i+b_i+b_j,s+a_i+a_j+b_j),C=\max(s+a_j+b_i+b_j,s+a_i+a_j+b_i)\)

那么\(1\)式即为\(\max(A,B)\),\(2\)式即为\(\max(A,C)\)。

假设\(i\)排在\(j\)前不会更差,那么就有\(\max(A,B)\le \max(A,C)\)

注意到\(B\le C\Rightarrow \max(A,B)\le \max(A,C)\)。这可以通过讨论\(A,B,C\)三者的大小关系得到。

充分性已经证明,那么就可以消去\(A\)。现在要解\(B\le C\)即\(\max(s+a_i+b_i+b_j,s+a_i+a_j+b_j)\le \max(s+a_j+b_i+b_j,s+a_i+a_j+b_i)\)

还是通过加法对\(\max\)的分配律得到\(\max(b_i,a_j)+s+a_i+b_j\le \max(b_j,a_i)+s+a_j+b_i\)

再化简,\(a_i+b_j-\max(a_i,b_j)\le a_j+b_i-\max(a_j,b_i)\)

即\(\min(a_i,b_j)\le \min(a_j,b_i)\)。

我们已经得到了排序的条件,但是这就够了吗?

不够。在C++中重载的运算符/比较规则要满足严格弱序(概念讲解在下方)。

小于等于号\(\le\)不满足非自反性,这个规则不是严格弱序。

如果换成\(\min(a_i,b_j)<\min(a_j,b_i)\),满足传递性但不满足不可比的传递性。

证明如下:

首先来证传递性。

命题\(p:\forall i,j,k\in \mathrm{N^+},\min(a_i,b_j)<\min(a_j,b_i)\land \min(a_j,b_k)<\min(a_k,b_j)\Rightarrow \min(a_i,b_k)<\min(a_k,b_i)\)

(证明先咕咕咕了QwQ)

考虑构造另一种排序的比较规则使之满足严格弱序。

当\(\min(a_i,b_j)=\min(a_j,b_i)\)时,考虑贪心,观察原来结论中的式子\(\min(a_i,b_j)\le \min(a_j,b_i)\),对于\(i\)来说,\(a\)尽可能小,\(b\)尽可能大,上式更可能成立。于是此时将\(a\)小的放在前面,或者将\(b\)大的放在前面即可。

得到了两种可行的排序方式,取其一便可:

\[P(i,j)=\begin{cases} a_i<a_j & \min(a_i,b_j)=\min(a_j,b_i)\\ \min(a_i,b_j)<\min(a_j,b_i) & Otherwise. \end{cases} \]

\[Q(i,j)=\begin{cases} b_i>b_j & \min(a_i,b_j)=\min(a_j,b_i)\\ \min(a_i,b_j)<\min(a_j,b_i) & Otherwise. \end{cases} \]

对于本题而言,还有另一种神秘而不自然可行的排序方式:

令\(d_i=sgn(a_i-b_i)\),设计排序函数:

\[F(i,j)=\begin{cases} d_i<d_j & d_i\ne d_j\\ a_i\le a_j & d_i=d_j\le 0\\ b_i>b_j & d_i=d_j=1 \end{cases} \]

我们将\(\min(a_i,b_j)\le \min(a_j,b_i)\)拆成逻辑表达式得到:

\[(a_i\le a_j\lor b_j\le a_j)\land (a_i\le b_i\lor b_j\le b_i) \]

经验证\(F(i,j)\)满足上式,且可以证明其为严格弱序,可以用于C++排序。

后悔法

正着直接找到最优解不好想,就随便选择决策,遇见更好的再后悔。

一道例题

luogu Work Scheduling G

约翰有太多的工作要做。为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。 他的工作日从 \(0\) 时刻开始,有 \(10^9\) 个单位时间。在任一时刻,他都可以选择编号 \(1\) 到 \(N\) 的 \(N(1 \le N \le 10^5)\) 项工作中的任意一项工作来完成。 因为他在每个单位时间里只能做一个工作,而每项工作又有一个截止日期,所以他很难有时间完成所有N个工作,虽然还是有可能。 对于第 \(i\) 个工作,有一个截止时间 \(D_i(1 \le D_i \le 10^9)\),如果他可以完成这个工作,那么他可以获利 \(P_i( 1\le P_i\le 10^9 )\). 在给定的工作利润和截止时间下,约翰能够获得的利润最大为多少。

Sol:

不想推式子,那就直接反悔做。

按截止时间排序依次考虑,如果当前任务在它的截止时间内还可以做,那就去做。如果不可以做了,那就尝试用它替换已经做了的任务中利润最小的一个。这就做完了。

选择不相交区间

\(Question\):

给出\(n\)个开区间\((l_i,r_i)\),选择尽量多个区间使之没有交点。

Sol:

按右端点升序排序。依次选即可。

正确性证明:

两个区间相交时,选右端点小的对后面的选择影响更小。

区间选点问题

\(Question\):

给出\(n\)个闭区间\([l_i,r_i]\),选尽量少的点使每个区间内都至少有一个点。

Sol:

按\(r_i\)递增,\(r\)相同时\(l_i\)递减排序。

从前往后依次考虑每个区间,若当前区间内没点,就选它的右端点\(r\)。

正确性证明:

按右端点递增排序后,若当前区间与后面的区间没有交点,那么随便选点都可以。若当前区间与后面的区间有交点,那么选右端点可以满足更多的区间。

改:

第\(i\)个区间要求至少要有\(k_i\)个点?

Sol:

每个区间从右往左依次取点直到满足即可。

区间覆盖问题

给出\(n\)个闭区间\([l_i,r_i]\),选择尽量少的区间覆盖\([s,t]\)。

Sol:

将区间按左端点递增排序,依次处理。

每次从覆盖了\(s\)的区间中选取右端点最大的一个,并更新\(s\)。直到所选择的区间包含了\(t\)为止。

正确性证明:

每次选右端点最大的是为了让剩余待覆盖的区间尽量小。

注意判断无解:某一步中没有覆盖了\(s\)的区间时无解。

双机流水作业调度问题

\(Question:\)

现在有\(n\)个作业,第\(i\)个作业分为两项内容,要按序先后在机器\(A\)和\(B\)上完成,分别需要时间\(a_i,b_i\)。一台机器同一时间只能进行一项作业。求完成所有作业的最短时间。

Another Question:

多机流水作业调度问题,将两个机器改为\(m\)个机器。是NP-hard问题。

Sol:

首先要注意到一个显然的性质:两台机器加工作业的顺序应该是相同的。

证明:

假设在\(A\)上\(i\)比\(j\)先加工,\(B\)上\(j\)比\(i\)先加工(\(j=i+1\),这里运用邻项交换法。),那么\(j\)在\(A\)上加工完成之前\(i\)无法进行在\(B\)上的加工,显然不会比交换前更优。

另一个显然的性质:\(A\)上时刻都有作业在被加工,而\(B\)上不一定。(过于显然,不予证明。)

定义\(c_i\)表示加工完\(i\)个作业的最短用时,可以写出式子:

\[c_i=\begin{cases} a_1+b_1 & i=1\\ \max \left \{ c_{i-1},\sum_{j=1}^{i}a_{j} \right \} +b_{i} & 2\le i\le n \end{cases} \]

这个式子与皇后游戏的式子是完全相同的,故结论相同。详见上文。

这告诉我们,模型的运用可以是类似的情景,也可以是式子的结论。

带期限和罚款的单位时间任务调度

\(Question:\)

有\(n\)个任务,每个任务有结束期限\(d_i\)和罚款\(w_i\),用时为\(1\)个单位时间。如果任务无法在结束期限前完成,将导致\(w_i\)的罚款。现在要使总罚款最小。

Sol:

要使总罚款最少,就要优先完成\(w_i\)较大的任务。对于每个任务,安排在尽量靠近\(d_i\)的时刻完成以给其他任务让出靠前的时刻。如果一个任务已经无法在结束时限前完成且必须被完成,就安排在尽可能靠近结束的时刻完成,理由同前一条。

标签:总结,le,min,max,大臣,区间,排序,贪心
From: https://www.cnblogs.com/EmilyDavid/p/18624865

相关文章

  • static修饰成员方法、static修饰成员的特点总结、浅聊主方法-java se进阶 day01
    1.工具类的介绍工具类不是用于描述事物的类,而是帮我们完成事情的类(打工)如图当我们编写完这个类后,我们会发现一件事,这个类自己本身并没有意义,这个类完全是给用户进行调用方法的既然是专门给用户调方法,那我们就应该写的更简便点,创建对象,再拿着对象名调用过于麻烦,因此我们在这......
  • JDK监控和故障处理工具总结
    JDK命令行工具这些命令在JDK安装目录下的bin目录下:jps(JVMProcessStatus):类似UNIX的ps命令。用于查看所有Java进程的启动类、传入参数和Java虚拟机参数等信息;jstat(JVMStatisticsMonitoringTool):用于收集HotSpot虚拟机各方面的运行数据;jinfo(Configu......
  • KDT总结
    咕咕咕。学会了一点了。KDT维护了\(k\)维空间中的超长方体。每个结点及其子树都在同一超长方体中。KDT的实现与平衡树类似(其实在\(k=1\)时就是另类的平衡树,只不过不太优秀)。树上的每个结点都对应着\(k\)维空间中的一个点。然后随便维护一下信息就可以支持\(k\)维超长方体查询信......
  • 2024年年终总结
    年底了,也来个总结1、减肥成功从体检时候的77KG,即154近减到136斤,减了18斤。主要是跑步,偶尔还去爬爬香山,这小半年,健身卡没浪费。中间还顺便跑了个半马,成绩2小时内。减肥缘由来自,年初过年的时候,来自老丈人和媳妇的告警。也是因为疫情三年,几乎没有锻炼。疫情之前,周末还去游游泳......
  • C语言常见错误总结
    语法错误 -括号不匹配:在函数定义、条件语句、循环语句等使用括号的地方,忘记添加或多添加括号,会导致编译错误。例如, if 语句中条件表达式括号不匹配,编译器会提示语法错误信息,指出缺少或多余的括号位置,仔细检查括号的成对性可避免。-分号缺失或多余:C语言语句以分号结束......
  • 平衡树总结
    从BST引入。我们要高效查找一个值,那么在保证左儿子小于右儿子的二叉树上跳,期望\(O(d)\),\(d\)为深度。二叉搜索树BST最好\(O(\logn)\),最坏\(O(n)\)。左子树的权值小于根的权值小于右子树的权值。P用没有。替罪羊树是一种依靠重构来维持平衡的重量平衡树。在插入删除时发现......
  • 链剖分总结
    来解决树上DS问题。因为没有能够直接高效维护树型结构的DS,于是把树剖分成链,然后拿序列上的DS去维护每一条链的信息。树链剖分有很多种:轻重链剖分,长链剖分,虚实链剖分。轻重链剖分这里是轻重链剖分。常数很小。其实不一定要用线段树维护,但用线段树维护是最常见的。支持换根,路......
  • 鸿蒙Next ArkTS编程规范总结
    一、目标和适用范围ArkTS编程规范参考业界标准及实践,结合ArkTS语言特点,旨在提高代码的规范、安全和性能,适用于开发者使用ArkTS编写代码的系统开发或应用开发场景。二、规则来源ArkTS在TypeScript基础上强化静态检查和分析,部分规则源于《OpenHarmony应用TS&JS编程指南》,并为ArkT......
  • 79.尚庭公寓项目总结收获
    单体项目技术来自尚硅谷:https://www.bilibili.com/video/BV1At421K7gP/?spm_id_from=333.337.search-card.all.click&vd_source=eb2341710c995d8261ecc99fdd066ba71.Typora的使用用的其实就跟博客园写记一样的markdown形式但我是习惯于win自带的记事本或是直接博客园但是......
  • 大语言模型学习工具及资源总结和落地应用
            当前,随着人工智能技术的迅猛发展,大语言模型(LargeLanguageModels,LLMs)在各个领域的应用日益广泛。以下是国内外常见的大语言模型工具、已经落地部署的应用以及学习相关的网站和资源的详细介绍。一、国内外常见的大语言模型工具国际大语言模型1.OpenAIGPT......