思想:从起点到终点,始终做当下“看起来最好”的选择(局部最优),不回溯,逐步构造解。
适用前提:
贪心选择性质:存在某个最优解,它的第一步与贪心选择一致;
最优子结构:选完这一步后,余下子问题的最优解与原问题的最优解可拼接。
正确性证明常用法:
交换论证:把任意最优解通过交换步骤改造成以贪心选择开头的最优解;
数学归纳/反证,或借用结构理论(如拟阵)与次模性。
活动安排问题

思路(贪心策略)
把所有活动按结束时间从小到大排序;从前往后扫,遇到一个活动的开始时间不早于上一个已选活动的结束时间,就把它选入。
直觉:越早结束,越不“占坑”,为后续留下最大空间。
正确性证明
贪心选择性质(交换论证)
设活动按结束时间排序为 且 。
令 为贪心解,首先选择 。令 为任一最优解(活动数最多),其第一项设为 。
若 ,则与贪心一致。
若 ,由于 ,把 的第一项 用 替换,得到解 。
对 中其余活动 ,它们的开始时间均满足 ,因此与 仍相容,活动总数不变。
于是存在一个最优解以 开头。
结论:选择“最早结束”的活动不会降低最优性,贪心第一步是安全的。
最优子结构(归纳)
选定 后,剩余可选活动集合为 。
原问题的一个最优解等于 在 上的最优解。
对 递用同样的“按结束时间最早”规则,结合数学归纳法,贪心算法整体最优。
伪代码
# 输入:activities = [(s1, f1), (s2, f2), ..., (sn, fn)]
# 约定:相容当且仅当 s_j >= f_i 或 s_i >= f_j(允许“贴边”)
def select_activities(activities):
# 1) 按结束时间升序
acts = sorted(activities, key=lambda x: x[1])
A = [] # 选择的最大相容集合
last_finish = -inf # 上一个入选活动的结束时间
for s, f in acts:
if s >= last_finish:
A.append((s, f))
last_finish = f
return A # A 的长度即最多能安排的活动数
复杂度
时间复杂度:
迪杰斯特拉算法
原创
贪心算法
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法