贪心
贪心(Greedy Algorithm)
这个带有些许贬义的名字可以直观看出算法的,因为想要最多的所以目光短浅,每一步选择都采取当下选择最优解,从而导致全局最优的算法策略
核心思想
- 局部最优从而导致全局最优
- 不会回溯:一旦做出选择就不再改变或者回退
- 短视性
应用
- 活动选择(安排最多但是不冲突的活动
- 霍夫曼编码(数据压缩
- 最小生成树
- 最短路径
- 硬币找零
- 分数背包问题
(让我慢慢遇见这些问题吧。。。
在看见贪心算法时大家应该会有一种稍稍怀疑但是喜悦的感觉,因为如此省心就可以解决问题,实则不然,在使用贪心算法前,一定要严格证明这个问题是具有贪心性质的!!!
1.合并果子
题目:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种果子,数目依次为 1,2,9。可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。所以多多总共耗费体力 =3+12=15。可以证明 15 为最小的体力耗费值。
解读
这是一个经典的合并果子问题。优先队列(最小堆)解决
1 |
|
Q:为啥这种算法就能精力消耗最小呢?
ans:合并次数是固定的:n堆果子需要n-1次合并
每个果子的重量在总代价中被计算的次数等于它在树中的深度
要最小化总代价,应该让重的果子尽量少被合并(放在浅层),轻的果子可以多被合并(放在深层)。
豁然开朗
2.彻底怒了
贪心问题总是判断出过后要写出合理的代码实现,但是却往往卡在这一步。分析归类此题需要用何种方法解决其实是第一步也是最重要的一步,但这并不意味着万事大吉
题目描述
金将军有两个长度为 n 的字符串 s,t,他认为一个字符串的愤怒值为其 CDNL 子串的个数。
现在,他想在 s 中选出一个长度至多为 m的子串 s’,在 t 中选出一个长度至多为 k 的子串 t’,使 s’,t’ 按顺序拼接后的字符串的愤怒值最大,你需要帮他求出这个值。
子串为原字符串中连续的一段字符组成的字符串。
碎碎念
笔者卡住的原因是跨界情况比较复杂,且内部匹配数的快速计算需要滑动窗口技巧,不是简单贪心能一次得到。
这个问题其实是一个受限最值子串选取+拼接模式匹配的优化问题,需要分情况仔细讨论并预处理,一想到会有不同的拼接情况,so nerve-racking
三种情况
如果列举的话
- 只出现在前一个字符串里且都为整个的连续子串,另一个字符串贡献为零
- 互换过来
- 都有贡献而且两者拼接部分不整,共同在拼接处形成一个
CDNL
期末周结束我会回来的。。。
