计算机算法:贪心算法的概念、设计思路与经典问题(详细分析与总结)

目录

贪心算法的概念

贪心算法的设计思路

贪心选择性质

最优子结构

贪心算法的经典问题

活动选择问题

最小生成树

分数背包


贪心算法的概念

求解最优化问题的算法通常需要经过一系列的步骤,在每个步骤都面临多种选择。对于许多最优化问题,使用动态规划算法来求最优解有些杀鸡用牛刀了,可以使用更简单、更高效的算法。贪心算法(greedy algorithm)就是这样的算法,它在每一步都做出当时看起来最佳的选择。也就是说,它总是做出局部最优的选择,寄希望这样的选择能导致全局最优解

贪心算法的设计思路

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

2.证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的。

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

我们如何证明一个贪心算法是否能求解一个最优化问题呢?并没有适合所有情况的方法,但贪心选择性质和最优子结构是两个关键要素。如果我们能够证明问题具有这些性质,就向贪心算法迈出了重要一步。

贪心选择性质

第一个关键要素是贪心选择性质(greedy-choice property):我们可以通过做出局部最优(贪心)选择来构造全局最优解。换句话说,当进行选择时,我们直接做出在当前问题中看来最优的选择,而不必考虑子问题的解。

最优子结构

如果一个问题的最优解包含其子问题的最优解,则称此问题具有最优子结构性质。此性质是能否应用动态规划和贪心方法的关键要素。

贪心算法的经典问题

活动选择问题

我们的第一个例子是一个调度竞争共享资源的多个活动的问题,目标是选出一个最大的互相兼容的活动集合。

假定有一个n个活动的集合S={a1,a2,…,an},这些活动使用同一个资源(例如一个阶梯教室),而这个资源在某个时刻只能供一个活动使用。每个活动ai,都有一个开始时间si和一个结束时间fi,其中0≤si<fi<∞。如果被选中,任务ai发生在半开时间区间[si,fi)期间。如果两个活动ai和aj满足[si,fi)和[sj,fj)不重叠,则称它们是兼容的。

在活动选择问题中,我们希望选出一个最大兼容活动集。假定活动已按结束时间的单调递增顺序排序:f1≤f2≤f3≤…≤fn-1≤fn。

分析:

最优子结构+贪心选择

令Ak是Sk的一个最大兼容活动子集,且aj是Ak中结束时间最早的活动,am是Sk中结束时间最早的活动。

若aj=am,则已经证明am在Sk的某个最大兼容活动子集中。

若aj!=am,令集合Ak'=( Ak-{aj} ) U{am},即将Ak中的aj替换为am。因为Ak中的活动都是不相交的,则Ak'中的活动都是不相交的,aj是Ak中结束时间最早的活动,而fm≤fj。由于|Ak'|=|Ak|,因此得出结论:Ak'也是Sk的一个最大兼容活动子集,且它包含am。

上面其实是通过反证法证明了贪心选择的正确性。

实现:可以递归,可以迭代

最小生成树

经典算法:Prim、Kruskal

Kruskal的证明中,基于反证法,使用了“连通区域”这一概念。

分数背包

给定 n 种可以分割的物品,物品的重量为 w[i],物品的价值为 c[i]。现挑选物品放入背包中,物品可以分割,假定背包能承受的最大重量为 V,问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大?

与01背包不同的是,分数背包具有贪心选择性质,因此每次选择单位重量的价值最高的物品,一直到背包装不下为止。

猜你喜欢

转载自blog.csdn.net/qq_41112170/article/details/127051392