◎学完你会
- 写区间调度 / 活动选择:按结束时间排序,依次选与已选不相交的区间;
- 理解"排序依据选对"是贪心的命门(该按结束、价值、不是开始/长度);
- 懂得哈夫曼、区间调度等"先排序再贪心"的通用套路。
1动一动:按结束时间贪心选区间
一组活动(开始-结束),选最多两两不相交的活动。先按结束时间排序,再从前往后,
只要开始 ≥ 上一个已选活动的结束,就选它。点「走一步」逐条判定:
原活动:[1,4] [3,5] [0,6] [5,7] [3,9] [5,9] [6,10] [8,11] [8,12] [2,14] [12,16]。
绿=已选,灰=跳过,红框=当前判断。贪心结果要能选到最多的一批。
2关键命令:排序贪心
按结束时间 r 升序排序活动 (l,r);
last = -1; // 上一个已选活动的结束
for(每个活动){
if(a.l >= last){ 选它; last = a.r; } // 不相交才选
}
为什么按结束排序:越早结束,越给后面的活动留出空间,是"贪心局部最优"。
若按开始或长度排序可能选到"又长又晚"的,反而做不了几个。
判断条件是 l≥last:是"开始晚于上一个结束",不是"结束早于上一个开始"。
⚠易错点
排序依据选错:按开始/长度/价值排,答案不是最优(该按结束时间)。
比较方向写反:判定 `l>=last` 写成 `l>=a.r`,逻辑错。
没排序直接贪:乱序逐个选,得到的是局部而非最优。
忘记更新 last:选了之后 last 没改成新结束,后续判断错。
?跨学科:先排序再取舍,是项目管理基本功
排课表、会议室排期、直播档期,都是"先按结束时间排,再尽量多塞不冲突的"。
这也是贪婪策略在日常里的体现:先抓住最有把握、最早能收尾的,腾出更多空间。
哈夫曼编码"每次合并最小的两个",同样是排序+贪心。
✎练一练
活动选择(选最多不相交区间)贪心时应按什么排序?
越早结束越能给后面的活动让出空间,所以按结束时间升序——选 B。
证明题:为什么区间调度按"最早结束"贪心能得到最多不相交区间?
答案(交换论证):若最优解的第一条是 X,而贪心选的是结束更早的 Y(Y.r ≤ X.r),把最优解里的 X 换成 Y 仍不相交、数量不变,所以贪心解不差于某个最优解。逐条替换后贪心解即达到最优数量。核心是"选结束最早的"永远不会被更晚结束的活动取代而吃亏。