每次都选当下的最优解,一步步得到全局的最优。
可以贪心的题目的性质
-
最优子结构性质:选择当前问题的最优决策不会影响子问题的最优决策。
-
贪心选择性:当前决策依赖于已经做出的决策,且决策一旦做出边不能更改。
证明贪心策略正确的方法
-
反证法:如果交换某两个元素后不会得到更好的答案,那么当前答案就是最优的。
-
归纳法:先算出边界的最优解,再证明下一步的最优解可以通过这一步的最优解得到。
寻找贪心策略的方法
-
直觉+归纳法。
-
领项交换法。
实现
普通贪心
后悔贪心
都有一种共性:将文字转化为数学关系进行推导。
经典的模型与方法
邻项交换法
在可以通过比较相邻两项得出交换或不交换一定不会更差时,可以用邻项交换法得到最优解。
注意邻项交换法得到的排序函数要满足严格弱序,并且排序完成后任意交换相邻元素都不会更优。这样才能保证算法正确。这一点详见拓展。
普通的邻项交换法例子
恰逢 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}\),排序即可。
拓展
一道推式子以及更严谨地考虑贪心策略的好题。
皇后有 \(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++排序。
后悔法
正着直接找到最优解不好想,就随便选择决策,遇见更好的再后悔。
一道例题
约翰有太多的工作要做。为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。 他的工作日从 \(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