1.问题
问题描述
有 n 项活动申请使用同一个礼堂,每项活动有一个开始时间和一个截止时间。如果
任何两个活动不能同时举行,问如何选择这些活动,从而使得被安排的活动数量达到最
多。
问题建模
设S ={1,2,…,n}为活动的集合,si和fi分别为活动 i 的开始和截止时间i =1,2,…,n,
定义:活动 i 和 j 相容 等价 si大于等于fj或sj大于等于fi, i≠j—可以画一条线把si与fi和sj和fj画上去结合理解
求 S 最大的两两相容的活动子集 A。–相容:两者之间不能冲突
2.解析
类似于动态规划,但是只顾眼前利益,不顾全局最优,正确性无法得到保障,证明是否最优解十分复杂。绝大部分贪心算法无法证明是最优解。
方法:把活动按照截止时间从小到大排序,使得f1 £ f2 £… £ fn,然后从前向后挑选,只要与前面选的活动相容,就可以把项活动选入 A。
(1) 选择活动 1,截止时间最早:活动 2,3 与活动 1 不相容,活动 4 与活动1 相容;
(2) 选择活动 4:活动 5,6,7 与活动 4 不相容,活动 8 与活动 4 相容;
(3) 选择活动 8:活动 9,10 与活动 8 不相容。
证明对于任意正整数K,算法的前K步都能导致一个最优解—活动个数最多了
定理:算法整型到第K步骤,选择K项活动,那么存在最优解A包含i1=1,i2,……,ik
证明(数学归纳法):
① 假设奠基:K=1时,命题成立
② 归纳假设:N = k时,假设成立
③ 证明成立:N=k+1时候,由N = K 推导N=K+1时成立
将S中的活动按照截止时间递增顺序排列。
(1)K = 1时,算法选择了活动1.(算法执行到第一步,选择结束时间最短的活动作为第一个活动)
设A={i1,i2,…,ij}是问题的一个最优解
如果i1 = 1,那么存在最优解包含了活动1.得证
如果i1 ≠ 1,那么用1替换i1得到A’
A’ = (A – {i1})∪{1}
A’ 和A的活动个数相等,活动1比i1结束得更早,因此活动1和i2,…ij等活动也相容,于是A’也是问题得一个最优解,因此存在最优解包含了活动1.得证。
A = { i1,i2,…,ij}
A’ ={1 ,i2….,ij}
f1<fi1<si2 =>f1<si2 =>1和i2相容
(2) 假设对于任意正整数 k,命题正确。
令 i1 =1,i2 ,…,ik是算法前 k 步顺序选择的活动,根据归纳假设,一个规模为n 的问题的最优解,当算法步骤为 k 时,i1=1,i2,….,ik为前 k 个最优解:
1) 构建问题最优解 A:由归纳假设,问题 S 存在一个最优解 A 由前 k 个和 S 中剩下活动中选出部分,即
A={i1,i2,….,ik}∪B
其中 B 必然是 S 中剩下活动中与i1,i2 ,…,ik相容的活动SB(令SB是 S 中剩下活动中与i1,i2 ,…,ik相容的活动)的最优解。
证明(反证法):如果 B 不是SB的最优解,必然存在 B’是SB的最优解,即|B’|>|B|,则A={ i1,i2,….,ik }∪B'将比 A 的活动更多,与 A 是最优解矛盾。因此,B 是SB的最优解。
2)分离最优解 B 的一个最早结束任务:由(1)得算法第一步选择结束时间最早的活动总是导致一个最优解。对于子问题SB存在一个包含选择结束时间最早的活动ik +1的最优解B* ={ik+1,...},B*和 B 都是最优解,于是
A={i1 =1,i2 ,...,ik}∪B={i1 =1,i2 ,...,ik}∪B* ={i1 =1,i2 ,...,ik ,ik+1}∪(B*-{ik+1})包含前K+1的活动,得证。
3. 设计
C++伪代码
(1) A={1}
(2) j=1
(3) for i=2 to n do
(4) if si≥
(5) then A=A∪{i}
(6) j=i
(7) return A
实验图片~:
4. 分析
O(n)
5. 源代码地址
https://github.com/Lin02993/Algorithm-Analysis-and-Practice-on-the-job