贪心算法最难的部分就是正确性的证明,常用的方法有归纳法(对算法步数归纳、对问题归纳)和交换论证法(从最优解出发,不变坏地替换,得到贪心策略的解)。下面以三个例子说明这些正确性证法。
我的个人博客上的原文链接
S = { 1 , 2 , … , n } S = \{ 1,2,…,n\} S={1,2,…,n}为n项活动的集合, s i 和 f i s_i和f_i si和fi分别为活动i的开始和结束时间,活动i与j相容当且仅当 s i ≥ f j 或 s j > = f i s_i \geq f_j或s_j>=f_i si≥fj或sj>=fi,求最大的活动集
按截止时间排序
伪代码:
定理:算法Select执行到第k步,选择k项活动 i 1 = 1 , i 2 , … , i k i_1=1,i_2,…,i_k i1=1,i2,…,ik,那么存在最优解A包含$ i_1=1 ,i_2,…,i_k $
只要此定理成立,算法至多到第n步得到最优解
归纳基础:设 S = { 1 , 2 , … . n } S = \{1,2,….n\} S={1,2,….n} 是活动集,活动按截止时间递增顺序排序,k=1,证明存在最优解包含活动1
任取最优解A,A中的活动按照截止时间递增的顺序排列,如果A的第一个活动为j,j不为1,令
A ′ = ( A − { j } ) ∪ { 1 } A' = (A-\{j\}) ∪\{1\} A′=(A−{j})∪{1}
由于 f 1 < = f j , A ′ f_1 <= f_j ,A' f1<=fj,A′ 也是最优解,而且含有1
归纳步骤:
假设命题对k为真,证明对k+1也为真
算法执行到第k步,选择了活动 i 1 = 1 , i 2 , … , i k i_1=1,i_2,…,i_k i1=1,i2,…,ik 根据归纳假设存在最优解A包含 i 1 = 1 , i 2 , … , i k i_1=1,i_2,…,i_k i1=1,i2,…,ik ,设最优解A包含$i_1=1,i_2,…,i_k $ ,A中剩下的活动选自集合$S’= { i | i ∈ S , s_i \geq f_k } $ ,且 A = { i 1 , i 2 , … , i k } ∪ B A = \{i_1,i_2,…,i_ k\} \cup B A={i1,i2,…,ik}∪B ,B一定是 S ′ S' S′ 的最优解
根据归纳基础,存在$S’ $ 的最优解B含有 S ′ S' S′ 中的第一个活动,设为 i k + 1 i_{k+1} ik+1 ,且$|B’| = |B| $,于是
n个集装箱1,2…,n装上轮船,集装箱i的重量为 w i w_i wi ,轮船载重量限制为 c c c ,无体积限制。如何使装上船的集装箱最多。(假设每个集装箱重量小于c)
将集装箱按照从轻到重排序,轻者先装
任务集合S,$\forall i∈S $ , d i 为 截 止 时 间 , t i 为 加 工 时 间 , 均 为 正 整 数 d_i为截止时间,t_i为加工时间,均为正整数 di为截止时间,ti为加工时间,均为正整数
一个调度f:S→N,f(i)为任务i的开始时间。求最大延迟达到最小的调度,即求f 使得
按照截止时间 d i d_i di从小到大选择任务,安排时不留空闲时间
伪代码:
上述算法的解的性质:没有空闲时间,没有逆序(不存在 f ( i ) < f ( j ) , d i > d j f(i)<f(j) , d_i > d_j f(i)<f(j),di>dj)
命题1:所有没有逆序、没有空闲时间的调度具有相同的最大延迟
命题1证明: f 1 和 f 2 f_1和f_2 f1和f2都没有逆序,具有相同截止时间的任务必须被连续安排。在这些连续安排的任务中最大延迟是最后一个任务,被延迟的时间只与已安排任务加工时间之和有关,与任务标号无关。
证明思想:从一个没有空闲时间的最优解出发,在不改变最优性的条件下,转变为没有逆序的解。
交换相邻逆序任务(i,j)不影响最优性: