最优流水作业调度问题
该算法是如此经典以至于 ACM 界已经有该算法的题目,下面是北大 PKU POJ 第 2751 题 Saving Endeavour(我校的 BOJ 上也有,不过是从 POJ 上照搬过来的): 有 2 台机器,n 件任务,必须先在 S1 上做,再在 S2 上做。任务之间先做后做任意。求 最早的完工时间。 双机调度问题 Johnson 算法简析: 1) 把作业按工序加工时间分成两个子集, 第一个集合中在 S1 上做的时间比在 S2 上少, 其 它的作业放到第二个集合。 先完成第一个集合里面的作业, 再完成第二个集合里的作业。 2) 对于第一个集合,其中的作业顺序是按在 S1 上的时间的不减排列;对于第二个集合, 其中的作业顺序是按在 S2 上的时间的不增排列。
最优流水作业调度问题
摘要
本文给出了双机流水作业调度的 Johnson 算法, 并结合 POJ 上的一道题目详述了该算法 的具体编程实现和应用。 关键词: 双机流水作业调度 Johnson 算法
正文
流水作业是并行处理技术领域的一项关键技术,它是以专业化为基础,将不同处理对象的 同一施工工序交给专业处理部件执行,各处理部件在统一计划安排下,依次在各个作业面上完 成指定的操作。 流水作业调度问题是一个非常重要的问题, 其直接关系到计算机处理器的工 作效率。然而由于牵扯到数据相关、资源相关、控制相关等许多问题,最优流水作业调度问 题处理起来非常复杂。已经证明,当机器数(或称工序数)大于等于 3 时, 流水作业调度问 题是一个 NP-hard 问题(e.g 分布式任务调度) 。粗糙地说,即该问题至少在目前基本上没有 可能找到多项式时间的算法。只有当机器数为 2 时,该问题可有多项式时间的算法(机器数 为 1 时该问题是平凡的) 。 我们先给出流水作业调度的定义: 设有 n 个作业,每一个作业 i 均被分解为 m 项任务: Ti1 , Ti2 , … , Tim (1 ≤ i ≤ n,故 共有n × m个任务), 要把这些任务安排到 m 台机器上进行加工。 如果任务的安排满足下列 3 个条件, 则称该安排为流水作业调度: 1. 每个作业 i 的第 j 项任务Tij (1 ≤ i ≤ n, 1 ≤ j ≤ m) 只能安排在机器Pj 上进行加工; 2. 作业 i 的第 j 项任务Tij (1 ≤ i ≤ n, 2 ≤ j ≤ m)的开始加工时间均安排在第j − 1项任务 Ti,j −1 加工完毕之后,任何一个作业的任务必须依次完成,前一项任务完成之后才能开 始着手下一项任务; 3. 任何一台机器在任何一个时刻最多只能承担一项任务。 最优流水作业调度是指: 设任务Tij 在机器Pj 上进行加工需要的时间为t ij 。 如果所有的t ij (1 ≤ i ≤ n, 1 ≤ j ≤ m)均 已给出, 要找出一种安排任务的方法, 使得完成这 n 个作业的加工时间为最少。 这个 安排称之为最优流水作业调度。 前面已经说过,当m ≥ 3时该问题是 NP 问题,这里我们只给出m = 2时时间复杂度在多 项式以内的 Johnson 算法。 求解流水作业调度问题的 Johnson 算法具体描述如下: 1) 设a[i]和b i (0 ≤ i < ������)分别为作业 i 在两台设备上的处理时间。建立由三元组(作业 号,处理时间,设备号)组成的三元组表d。其中,处理时间是指每个作业所包含的两 个任务中时间较少的处理时间。
Johnson 算法的时间取决于对作业集合的排序,因此,在最怀情况下算法的时间复杂度 为O(nlogn),所需的空间复杂度为O(n)。
c 语言代码如下: #include <stdio.h> #include <memory.h> #include <algorithm> using namespace std; const int MAXN=10005; struct TNode { int s1,s2; }ws[MAXN]; int topf,tops; int n; bool operator<(TNode x,TNode y) { if (x.s1<x.s2&&y.s1>=y.s2) return true; if (x.s1<x.s2&&y.s1<y.s2) return x.s1<y.s1; if (x.s1>=x.s2&&y.s1>=y.s2) return x.s2>y.s2; return false; } int max(int x,int y) { return x>y?x:y; } void Work() { sort(ws,ws+n); int i,t1=0,t2=0; for (i=0;i<n;i++) { t1+=ws.s1; t2=max(t1,t2)+ws.s2; } printf("%dn",t2); }
设n = 4, a0 , a1 , a2 , a3 = (3,4,8,10)和 b0 , b1 , b2 , b3 = (6,2,9,15)的作业 0 的三元组为 (0,3,0),作业 1 的三元组为(1,2,1)。 如图(a)所示。 2) 对三元组表按处理时间排序,得到排序后的三元组表 d。如图(b)所示。 3) 对三元组表的每一项d[i](0 ≤ i < ������),从左右两端生成最优作业排列c[j](0 ≤ j < ������),c[j] 是作业号。如果d[i]设备号为 1,则将作业 i 置于 c 的左端末尾,否则置于 c 的右端 末尾。如图(c)所示,由两端向中间存放。 a) 三元组表 作业号 0 1 2 3 b) 按处理时间排序 作业号 1 0 2 3 c) 最优作业排列 (0, 2, 3, 1) d) 最优调度方案 p1 p2 3 6 8 9 10 15 4 2 处理时间 2 3 8 10 设备号 1 0 0 0 处理时间 3 2 8 10 设备号 0 1 0 0
void Read() { int i; while (scanf("%d",&n)&&n) { for (i=0;i<n;i++) scanf("%d%d",&ws.s1,&ws.s2); Work(); } } int main() { Read(); return 1; }
ห้องสมุดไป่ตู้