贪心算法与活动选择问题和背包问题

前面的几篇博文都是围绕动态规划求解最优解问题,但是最优解还有另一种算法就是贪心算法。

动态规划会研究一个问题是否具有最优子结构,然后把问题化为子问题,一般自底向上的求解子问题最终组合出原问题的最优解,但是有些问题用动态规划法就有些“杀鸡用牛刀”的感觉,贪心法显得更加简洁直观

所以贪心算法的核心思想是什么呢?就是通过每一步做出局部最优的选择从而达到全局最优的结果。这一点是可以证明的,不过也不是所有的最优问题都可以用这个实现,但是有些问题比如活动安排,背包问题,哈夫曼编码最小生成树等都可以用贪心算法高效简洁的实现

首先看活动选择问题:

假定有一个n个活动的集合S={a1,a2,a3...an},这些活动使用同一个资源(例如同一个活动教室),而这个资源在某一时刻只能供一个活动使用,每个活动ai都有一个开始时间si和结束时间fi,如果被选中,ai发生在[si,fi)区间。如果ai, aj 两个活动的[si,fi), [sj,fj)不重叠,就称他们为兼容的。在活动选择问题中,希望选出一个最大兼容活动集


在这个图中可以看出最大兼容的活动可以是{a1,a3,a6,a8}也可以是{a2,a5,a7,a9}

对于活动选择问题,什么是贪心选择呢?直观上应该是选完一个活动后,剩下的资源能被尽量多的活动使用。换句话说,如果活动已经按结束时间递增排好序,那么第一个选择就是a1,当然选择最早结束的活动为a1也不是唯一的贪心选法


上图表示已经按结束时间递增将活动排好序了

当做出这个贪心选则后,就只剩下一个问题,那就是寻找在a1结束后开始的活动,毕竟在a1之前的活动已经没有了

令Sk = {ai| si>=fk}表示在活动ak结束之后开始的活动集合,选择了a1之后,剩下的s1就是唯一需要求解的子问题,毕竟最优子结构的性质告诉我们,如果a1在最优解中,那么原问题的最优解由活动a1及子问题s1中活动组成


贪心算法通常都是自顶向下的设计:做出一个选择,然后求解剩下的那个子问题,而不是自底向上的求出很多子问题然后在做出选择

递归贪心算法

输入两个数组s[], f[]分别表示活动们的开始时间和结束时间,k指出要求解的子问题Sk,以及问题规模n,返回Sk一个最大兼容活动集,假定输入的活动已经按结束时间递增的顺序排好,添加一个虚拟活动a0其结束时间f0 = 0,这样S0就是完整的活动集合了,求解原问题调用(s,f,0,n)

伪代码如下

Recursive_Activity_Selector(s[],f[],k,n)

{

m = k+1;

//这一步是找到a开始时间在ak结束之后的第一个活动

while(m<=n&&s[m]<f[k])

m++;

//找得到,把这个添加到已找打活动集中,继续解决其他子问题

if(m<=n)

return {am}+Recursive_Activity_Selector(s,f,m,n);

else return null;

}

迭代贪心算法

可以很方便的将上面的尾递归形式改成迭代形式

伪代码:

Greedy_Activity_Selector(s[],f[])

{

n = s.length;

A = {ai};

   k = 1;

for(m=2;m<=n;m++)

{

if(s[m]>=f[k])

{A = A +{am}; k = m;}

}

return A;

}


贪心算法的原理

贪心算法通过做出系列选择来获得问题的最优解,在每个决策点上,它做出当前看来最佳的选择,一般的设计贪心算法的步骤包括:

1、将最优化问题转化成这样的形式:对其做出一个选择后,只剩下一个子问题需要求解

2、证明做出贪心选择后,原问题总是存在最优解

3、证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合就可得到原问题的最优解,也就是最优子结构性质


贪心与动态规划——背包问题

贪心和DP都用到了最优子结构性质,但是两者还是有差别。可以看这个经典的背包问题

0-1背包问题

n个商品,第i个商品价值vi,重wi,都是整数。希望拿走尽可能高的价值但是背包最多容纳W重的商品,W是一个整数。(也就是要拿就要完整的把这个商品拿走)

分数背包问题

与上面问题几乎一样,但是可以拿走商品的一部分,而不只是二元选择

两个问题都有最优子结构性质,但是用贪心算法能解决分数背包而不能解决第一个,因为第一个完整的拿走如果用贪心算法的话,会有剩下的空间不能好好利用

对于可以用贪心策略解决的分数背包,可以计算vi/wi,根据这个排序,先拿走性价比最高的以此类推



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值