一、问题定义
输入:
- n n n个活动组成的集合 S = { a 1 , a 2 , . . . , a n } S={\left \{a_1,a_2,...,a_n \right \} } S={a1,a2,...,an}
- 每个活动 a i a_i ai的开始时间 s i s_i si和结束时间 f i f_i fi
输出:
- 找出活动集合 S S S的子集 S ′ S' S′,使得 m a x ∣ S ′ ∣ max|S'| max∣S′∣,其中 ∀ a i , a j ∈ S ′ , s i ≥ f j \forall a_i,a_j \in S', s_i \ge f_j ∀ai,aj∈S′,si≥fj或 s j ≥ f i s_j \ge f_i sj≥fi
二、贪心求解
2.1 提出贪心策略
通过观察问题特征,构造贪心选择,并通过举反例的方式筛选掉得不到最优解的贪心策略。
通过举例可以发现,策略3可以得到最优解:
接下来就是要证明策略3能够保证得到最优解。
2.2 贪心正确性证明
通常可以采用替换法进行证明:
假设存在一个最优方案,不断地等价替换最优方案里的内容(始终保持为最优方案),直至与贪心所得到的结果相同,即可证明贪心解不劣于最优解,也就证明了贪心解可以保证得到最优解。
从前往后依次检查最优解和贪心解,如果活动相同,则无需替换;如果活动不同,则将最优解里的活动替换为贪心解里的活动,此时并不会影响最优解的活动个数。因为在贪心解中优先选择的是先完成的活动,所以替换过去的活动不会晚于原活动结束,替换之后可以为最优解后续的活动提供更大的空间,至少不会影响后续活动,故依然保持最优解。
最终,可以将最优解替换为贪心解,证明了贪心解不劣于最优解,完成证明。
2.3 伪代码
三、贪心算法总结
3.1 贪心算法的特点
(1)贪心法适用于组合优化问题
(2)求解过程是多步判断过程,最终的判断序列对应于问题的最优解
(3)依据某种“短视的”贪心选择性质判断,在一系列步骤下,每一步有一组选择,作出当前来看最好的选择
(4)贪心法必须进行正确性证明
(5)证明贪心法不正确的技巧:举反例
贪心法的优势:算法简单,时间和空间复杂性低
3.2 适用条件
贪心算法适用条件:
- 贪心选择性:一个最优问题的全局最优解可以通过局部最优选择得到
- 问题具有最优子结构:一个最优问题的最优解包含它的子问题的最优解
3.3 贪心正确性证明思路
贪心算法正确性证明:
证明问题具有贪心选择性(证明最优解中一定包含的第一步,地位相当于数学归纳法的首项)
证明问题具有最优子结构(证明最优解中去掉第一步后剩下的依然是子问题的最优解;通常使用反证法,假设不是最优解,则存在子问题的别的最优解,加上第一步后,比原问题的最优解还要好,与原问题是最优解产生了矛盾)
是用数学归纳法对算法正确性进行证明(利用贪心选择性和最优子结构)
上述已经阐述了正确性的证明方法,以下是另一种表述,与上面本质相同,只是上面的使用数学语言更多,更加严谨。
(1)替换法
假设存在一个最优方案,不断地等价替换最优方案里的内容(始终保持为最优方案),直至与贪心所得到的结果相同,即可证明贪心解不劣于最优解,也就证明了贪心解可以保证得到最优解。
(2)数学归纳法
方法:第一归纳法、第二归纳法
证明步骤:
①叙述一个有关自然数 n n n的命题,该命题断定该贪心策略的执行最终将导致最优解。其中自然数 n n n可以代表算法步数或者问题规模
②证明命题对所有的自然数为真。归纳基础:从最小实例规模开始;归纳步骤:第一或第二数学归纳法