贪心算法–带期限的单机调度问题
算法求解问题:
已知n项作业 E={1, 2, … ,n}要求使用同台机器完成,而且每项作业需要的时间都是1。第k项作业要求在时刻dk之前完成, 而且完成这项作业将获得效益pk,k=1, 2, … , n 。
现在我们要求解的是:
要在所给的作业集合中选出总效益值最大的相容子集。
(其中pk为算法的贪心标准)
算法思想:
proc GreedyJob(d, p, n) //带期限的单机作业安排算法
//d[1..n]和p[1..n]分别代表各项作业的限期和效益值,
//而且n项作业的排序满足:p1 >= p2 >= … >= pn
local J;
J:={1}; //初始化解集
for i from 2 to n do
if J 并上 {i} 中的作业是相容的 //检验规则:(放在后面解释)
then //对任一j ∈ J 并上 {i},作业期限≤d(j)的数量≤ d(j)个
J:= J 并上 {i}; // 将i加入解中
end{if}
end{for}
end{GreedyJob} //贪心准则:尽量选取效益大的作业安排 (该算法关键在于检验规则)
算法实例:
7是问题最优解
算法证明:
假设贪心算法所选择的作业集J不是最优解,则一定有相容作
业集I,其产生更大的效益值。证 I=J。
也就是说现在有两个集合,分别是:
贪心集:J
最有集:I
因为假设贪心算法得到的不是最优,那么必定存在一个最优,如果证明J=I则算法得证。
如果J不等于I则有以下关系:
1.最优I 是 贪心J的子集,显然不成立,既然贪心得到了更大的集合且合理那I又怎么能称为最优
2.贪心J 是 最优I的子集,显然也不成立,因为这样违背了贪心规则
3.那么只有第三种情况就是两个集合各自存在对方没有的元素
即至少存在两个作业a,b 其中a属于J,不属于I , b属于I,不属于J
此时对于a,pa>=I中所有的pb,因为如果将I和J从大到小排列后逐一比较,到a时与相应位置的b比较由于贪心算法,此时会选择大的,因为选择了a所以pa>=pb
设SJ和SI是J和I两个可行解的调度序列:
其中i是既属于J又属于I的一个作业,其调度时刻在两个集合中如图分别是[t,t+1]和[t’,t’+1]。
现在在两个调度表中做如下调整:
1.t<t’
将SJ中t‘时刻的作业和i相交换,如果存在则交换,如果不存在则直接将i移过去。
(新调度表依然可行,因为t‘时刻的作业提前完成肯定是可行的,而t时刻的i在最优解中在t’时刻执行是可行的所以在J中移动后依然可行)
2.t’<t
操作与上述类似,同样新的调度表依然可行
对J和I 中所有作业如此操作后,得到的新SJ和SI的共有作业将会在相同时间进行调度,而不相同的则如下:
此时将 I中的ta时刻作业如果替换成a,则对于I 来说,效益值并不会减少,且替换后仍然可执行。重复上述转换后,I其实也就已经替换成了J,且效益值不会减小,所以J其实就是等于I的。证毕
检验规则
好,现在回过头来再看一下前面说到的检验规则,也就是加入i后J是否仍然可行。
首先我们需要找到一个特定序列,该序列为按照作业期限的非降次序排列,设该序列为σ。
J是一个可行解,当且仅当J中的作业可以按照σ的次序而又不违反规则任何一个期限的情况来处理。
只有满足上述条件,加入i后的J才是可行的。