贪心算法的基本思想:在算法迭代的每一步,选择当前状态下最优解,不断重复这一过程,最终得到结果,但这个结果不一定是全局最优的。
算法的优点在于:简便,高效。缺点是:得到的解不一定正确。
贪心算法的分析策略:
- 在算法迭代的每一步,贪心算法的解至少要比其它算法好。
- 寻找一个简单的结构界限,在这个界限内,每一个有可能的解都有确定的值,然后说明贪心算法也在这个界限内。
- 逐渐改变其它方案,向贪心算法转变,而又不影响它的质量。
著名的贪心算法有:Kruskal, Prim, Dijkstra, Huffman, …
设计贪心算法的步骤:
- 将问题转换为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解。
- 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的。这种证明通常首先考察某个子问题的最优解,然后用贪心选择替换某个其它选择来修改此解,从而得到一个相似但更小的子问题。
- 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构。
贪心选择性质:通过做出局部最优(贪心)选择来构造全局最优解。也就是说,直接选择当前问题中看起来是最优的选择,而不必考虑子问题的解。
最优子结构:如果一个问题的最优解包含其子问题的最优解,则称此问题具有最优子结构性质。
常见的贪心算法问题:
不带权重的活动选择问题:
问题描述:分数背包问题:
问题描述:一个正在抢劫商店的小偷发现了n个商品,第i个商品的价值式是vi美元,重wi磅,对于每个商品,小偷可以拿走一部分,而不是只能做二元(0-1)选择,他的背包最多能容纳W磅的商品。他应该拿哪些商品呢?
算法设计思路:分数背包问题要区别于0-1背包问题,0-1背包问题不能采用贪心算法,需要用到动态规划。而分数背包问题可以采用贪心策略。传统的算法设计思路是将每件商品的性价比(wi/vi)排序,然后从大到小依次选择,这种方法需要的运行时间为O(nlogn)。这里给出一种只需要O(n)时间的算法设计方法:
对于商品集合的商品,我们没有必要知道所有商品的性价比排序,比如说,假设商品a1,a2,a3是性价比最高的三件商品,只要它们的重量之和不大于W,就没有必要知道它们的相对顺序,将它们三个全部放入背包即可。基于这种思想,可以设计如下算法:
1、首先利用线性查找算法找出物品单位价值的中位数m;
2、利用中位数m对所有物品进行划分成三个集合 WG ={Vi/Wi>m } WE = {Vi/Wi=m} WL = {Vi/Wi<m},计算 WG、WE、WL集合中物品的总重量;
3、若 WG>W,则不往背包中放任何物品,从Step1开始继续分解WG;
4、若 WG<W,则把WG中的物品全部放入背包,并且尽可能多地放WE中的物品;
5、若 WG+WE>=W,则把物品全部放入结束;
6、若 WG+WE<W,则把WG+WE的物品全部放入,从Step1开始继续分解WL。
算法参考:http://blog.csdn.net/u010339647/article/details/50588554
此递归算法满足T(n) = T(n/2)+n,由此可以计算运行时间为O(n)。