贪心算法理论解

贪心算法,顾名思义就是贪得当前情况下的最优解(局部最优解),在某些情况下,每次的选择如果都依赖于前面的依次选择而不受后续操作的影响,局部最优解组成全局最优解(最优子结构),就可以用贪心法求解。

贪心法的基本概念很简单,但是可以有很多经典的应用:

目录

背包问题

最优装载问题

部分背包问题

乘船问题

区间问题

选择不相交区间

区间选点问题

区间覆盖问题

Huffman编码


背包问题

最优装载问题

最优装载问题是最简单、最容易理解的贪心背包问题。给出n个物体,第i个物体的重量为wi,不可分割。选出尽量多的物体,使总质量不超过C。

由于只关心数量,所以装轻的性价比要比装重的高——先把所有物体按照重量排序,再从小的开始放进背包,直到装不下为止。

部分背包问题

给出n个物体,第i个物体的重量为wi,价值为vi。在总质量不超过C的情况下让总价值尽量高。每一个物体可以只取一部分。

和上一道题不同,这里质量和价值都是需要考虑的因素。“总质量限定的情况下价值尽量高”,也就是说价值和质量的“价值密度”要尽量高。所以将所有物体的价值密度(double价值/质量)从大到小排序后放入背包,直到装满为止。

一般情况下除了最后一个物体,其他放进背包的物体都不分割。

乘船问题

n个人,其中第i个人重量为wi。每艘船最大载重量为C,且最多只能做俩人。要求运送所有人的最少的船只数。

这类题的考虑思路是,对于最轻的人,安排最重的人和他坐一条船,这样“浪费”才会最少。如果最重的人和最轻的人一条船都无法承载,那么最重的人只能单独乘一条船,最轻的人再尝试和第二轻的人共渡。

代码实现方面,可以用两个下标i和j表示当前数组的首端(最轻的人所在位置)和末端(最重的人所在位置)。在循环中,如果最轻的人和最重的人可以共渡,则i++并j--。如果不行,则只需要j--。直到全部上船为止。

该程序的复杂度仅为O(n),显然是最优算法。


区间问题

选择不相交区间

数轴上有n个开区间(ai,bi),要求尽量选择多个区间使其不相交。

不相交区间问题的解决首先将这些开区间按照右端点bi从小到大排序,并取排序后的第一段(这一段一定要取),接着按照bi从小到大遍历,判断如果遍历到的一段的ai在前一段的bi-1之后,则可以取这一段。

关于为什么要取第一段,可以分两种情况考虑:
第一种情况是b1<b2且a1>a1,也就是第一段处在被第二段“包围”的状态。这种情况下选小区间更划算吗,因为不仅本次取的数目不会减小,还给后续区间留下了位置。

第二种情况是b1<b2且a1<a2,这种情况也很好判断,由于第一段在前面“伸出来”的一段不会对任何后续产生影响,后面部分还短小(不会对后续造成影响),所以果断选第一段。

区间选点问题

数轴上有n个闭区间[ai,bi]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。

首先一个基本思想是,如果一个区间被另一个大区间“包裹”,那么在小区间内取点则大区间一定也满足。所以在区间包含情况下,大区间不需要考虑。

同理把所以区间按b从小到大排序(b相同时a从大到小排序->区间包含的情况,小区间在前面)。同样要取第一个区间,但是取的是第一个区间的最后一个点,那样可以尽量多满足后续区间。接着在当前b后找到第一个a,取该a所对应区间的末端点,同理可以满足多段。

区间覆盖问题

数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]。

本题思路仍然是区间包含和排序扫描,与上面不同的是需要进行一次预处理——将所有区间在起点s之前的所有部分都切掉,选择此时起点为s的最长区间,并将“新起点”设置为该最长区间的最右端点,重新开始一遍操作。递归或循环都可以解决。


Huffman编码

还记得之前提到的文件压缩吗?那就是Huffman编码的典型应用。可以将所有字符出现的频率列成一张表P并进行排列,然后创建一个新节点队列Q,每次合并两个节点后把新节点放到队列Q中。合并后的频率一定比合并前频率和大,所以Q内部一定是有序的。

类似于有序表的合并过程,每次检查P和Q的首元素即可找到频率最小的元素,时间复杂度为O(n)。排序后总程序的复杂度为O(nlogn)。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhqi HUA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值