贪心算法

    与动态规划算法类似,贪心算法通常用于最优化问题,贪心算法的思想是每步选择都追求局部最优,它在每一步都做出当时看起来最佳的选择,希望这样的选择能导致全局最优解。贪心算法并不保证得到最优解,但对很多问题确实可以求得最优解。贪心方法是一种强有力的算法设计方法,可以很好的解决很多问题。

活动选择问题

    假定有一个包含n个活动的集合S={a1,a2,•••,an},这些活动使用同一个资源,而这个资源在某个时刻只能供一个活动使用,每个活动ai都有一个开始时间si和一个结束时间fi,其中≤si

选择问题的最优子结构

    令Si表示在ai结束之后开始,且在aj开始之前结束的那些活动的集合,希望求解Sij的一个最大的相互兼容的活动子集,假定Aij就是这样的一个子集,其中包含活动ak,用c[i , j]表示集合Sij的最优解的大小,可得递归式
c[i, j] = c[i, k] + c[k, j] + 1

贪心递归算法

    贪心选择无需考虑所有的子问题就可以做出选择,贪心算法通常都是自顶向下的设计,做出一个选择,然后求解剩下的那个子问题,而不是自底向上地求解很多子问题,然后再做出选择。

RECURSIVE_SELECTOR(s, f, 0, n)
m = k + 1
while m <= n and s[m] < f[k]
  m = m + 1
if m <= n
  return {am} + RECURSIVE_SELECTOR(s, f, m, n)
else
  return null

迭代贪心算法

    很容易就可将递归算法转换为迭代形式。

GREEDY_ACTIVITY_SELECTOR(s, f)
n = s.length
A = {a1}
k = 1
for  m = 2 to n
  if s[m] >= f[k]
    A = A + {am}
    k = m
return A

贪心算法原理

    贪心算法通过做出一系列选择来求出问题的最优解,在每个决策点,它做出在当时看来最佳的选择,这种启发式策略并不保证总能找到最优解,但是对问题确实有效。
    可以按如下步骤来设计贪心算法:
1. 将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解;
2. 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的;
3. 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构。
    如果一个问题具有贪心选择性质和最优子结构两个关键要素,就可以使用贪心算法来求解一个最优化问题。

贪心选择性质

    一个关键要素是贪心选择性质:可以通过做出局部最优(贪心)选择来构造全局最优解。
    贪心算法与动态规划的不同之处:在动态规划中,每个步骤都要进行一次选择,但选择通常依赖于子问题的解,因此通常以自底向上的方式求解动态规划问题,先求解较小的子问题,然后是较大的子问题。在贪心算法中,总是做出当时看起来最佳的选择,然后求解剩下的唯一的子问题,贪心算法进行选择时可能依赖之前做出的选择,但不依赖任何将来的选择或是子问题 的解。

最优子结构

    如果一个问题的最优解包括其子问题的最优解,则称此问题具有最优子结构性质。这个性质也是是否能应用动态规划的关键要素,当应用于贪心算法时,通常使用更为直接的最优子结构。
    由于动态规划和贪心算法都利用了最优子结构性质,所以可能对一个需要贪心算法求解的问题使用动态规划求解,或者相反的情况,需要区分两者之间的差别。

哈夫曼编码

    哈夫曼编码可以很有效的压缩数据:通常可以节省20%-90%的空间,具体压缩率依赖于数据的特性。将待压缩数据看做字符序列,根据每个字符的出现频率,哈夫曼贪心算法构造出字符的最优二进制表示。每个字符用唯一的二进制串表示,称为码字,字符的编码方案有多种。这里考虑前缀码,前缀码指没有任何码字是其他码字的前缀,文件最优编码方案总是对应一棵满二叉树,即每个非叶结点都有两个孩子结点。

构造哈夫曼编码算法

    哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码。
    假定C是一个n个字符的集合,而其中每个字符c∈C都是一个对象,其属性c.freq给出了字符的出现频率,算法自底向上地构造出对应最优编码的二叉树T。它从|C|个叶结点开始,执行|C|-1个“合并”操作创建出最终的二叉树,算法使用一个以属性freq为关键字最小优先队列Q,以识别两个最低频率的对象将其合并,当合并两个对象时,得到的新对象的频率设置为原来两个对象的频率之和。

HUFFMAN(C)
n = |C|
Q = C
for i = 1 to n – 1
  allocate a new node x
  z.left = x = EXTRACT_MIN(Q)
  z.right = y = EXTRACT_MIN(Q)
  z.freq = x.freq + y.freq
  INSERT(Q, z)
return EXTRACT_MIN(Q)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值