贪心算法
一、基本概念
贪心算法每次做出当前看起来的最优解,也就是局部最优解,从而希望获取到全局的最优解,但是贪心算法并不保证可以得到最优解,贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性(即某个状态以后的过程不会影响以前的状态,只与当前状态有关。)
所以,对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二、贪心算法的基本思路
建立数学模型来描述问题
把求解的问题分成若干个子问题
对每个子问题求解,得到子问题的局部最优解
把子问题的解局部最优解合成原来问题的一个解
三、该算法存在的问题
不能保证求得的最后解是最佳的
不能用来求最大值或最小值的问题
只能求满足某些约束条件的可行解的范围
四、贪心算法适用的问题
贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。一般对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可以做出判断。
五、贪心选择性质
所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,换句话说,当考虑做何种选择的时候,我们只考虑对当前问题最佳的选择而不考虑子问题的结果。这是贪心算法可行的第一个基本要素。贪心算法以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用贪心算法求解的关键特征。
六、贪心算法的实现框架
从问题的某一初始解出发:
while (朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个解元素。
}
由所有解元素组合成问题的一个可行解;
七、例题分析
1.活动选择问题
假设有一个n个活动的集合 \(S=\{a_1,a_2,a_3,a_4,...,a_n\}\),这些活动使用同一个资源,而这个资源在某个时刻只能给一个活动使用,每个活动\(a_i\)都有一个开始时间\(s_i\)与结束时间\(f_i\),其中0\(\leqslant s_i\)<\(f_i\)<\(\infty\)。如果被选中,任务\(a_i\)发生在半开区间[\(s_i,f_i\))期间,如果两个活动\(a_i\)和\(a_j\)满足[\(s_i,f_i\))和[\(s_j,f_j\))不重叠,则称它们是兼容的,因此,若\(s_i \geqslant f_j\)或者\(s_j \geqslant f_i\),则称\(a_i\)和\(a_j\)是兼容的,在活动选择问题中,我们希望选择出一个最大兼容活动集。假定活动已经按照结束时间的单调递增顺序来排序:
例如,考虑下面的活动集合S:
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
\(s_i\) | 1 | 3 | 0 | 5 | 3 | 5 | 6 | 8 | 8 | 2 | 12 |
\(f_i\) | 4 | 5 | 6 | 7 | 9 | 9 | 10 | 11 | 12 | 14 | 16 |
对于这个例子 如果从\(s_i\)=0开始考虑的话,我们可以得出{\(a_3,a_9,a_{11}\)}这个子集,但它并不是一个最大的子集,因为子集{\(a_1,a_4,a_8,a_{11}\)}和{\(a_2,a_4,a_9,a_{11}\)}更大 |
1.1.贪心选择
对于这个活动选择问题,我们应该要找最早结束的活动,因为这样它的剩下的资源可以提供给更多的活动使用,这样我们就可以获得一个最大子集{\(a_1,a_4,a_8,a_{11}\)},当然选择最早结束的活动并不是这个问题的唯一的贪心选择。