概述
流水作业是并行处理技术领域的一项关键技术,它是以专业化为基础,将不同处理对象的同一施工工序交给专业处理部件执行,各处理部件在统一计划安排下,依次在各个作业面上完成指定的操作。
流水作业调度问题是一个非常重要的问题,其直接关系到计算机处理器的工作效率。然而由于牵扯到数据相关、资源相关、控制相关等许多问题,最优流水作业调度问题处理起来非常复杂。已经证明,当机器数(或称工序数)大于等于3时, 流水作业调度问题是一个NP-hard问题(e.g分布式任务调度)。粗糙地说,即该问题至少在目前基本上没有可能找到多项式时间的算法。只有当机器数为2时,该问题可有多项式时间的算法(机器数为1时该问题是平凡的)。
我们先给出流水作业调度的定义:
设有n个作业,每一个作业i均被分解为m项任务: Ti1,Ti2,…,Tim(1≤i≤n,故共有m∗n个任务), 要把这些任务安排到m台机器上进行加工。 如果任务的安排满足下列3个条件, 则称该安排为流水作业调度:
- 每个作业 i 的第 j 项任务Tij (1⩽i⩽n,1⩽j⩽m) 只能安排在机器 Pj 上进行加工
- 作业 i 的第 j 项任务 Tij(1≤i≤n,2≤j≤m) 的开始加工时间均安排在第 j−1 项任务Tij−1 加工完毕之后,任何一个作业的任务必须依次完成,前一项任务完成之后才能开 始着手下一项任务:
- 任何一台机器在任何一个时刻最多只能承担一项任务。
最优流水作业调度是指:
设任务τij在机器Pj上进行加工需要的时间为tij。 如果所有的tij(1⩽i⩽n,1⩽j⩽m)均已给出, 要找出一种安排任务的方法, 使得完成这 n个作业的加工时间为最少。 这个安排称之为最优流水作业调度。
前面已经说过,当m≥3时该问题是NP问题,这里我们只给出m=2时时间复杂度在多项式以内的Johnson算法。
求解流水作业调度问题的Johnson算法具体描述如下:
1、设 a[i]和 b[i] (0≤i<n)分别为作业 i 在两台设备上的处理时间。建立由三元组 (作业
号,处理时间,设备号)组成的三元组表 d。其中,处理时间是指每个作业所包含的两 个任务中时间较少的处理时间。
设 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) 所示。
(a)三元组表
作业号 0123 处理时间 32810 设备号 0100
2、对三元组表按处理时间排序,得到排序后的三元组表 d。如图(b)所示。
(b)按处理时间排序
作业号 1023 处理时间 23810 设备号 1000
3、对三元组表的每一项 d[i](0≤i<n), 从左右两端生成最优作业排列 c[j](0≤j<n),c[j]是作业号。如果 d[i]设备号为 1,则将作业 i 置于 c 的左端末尾,否则置于 c 的右端 末尾。如图©所示,由两端向中间存放。
(c)最优作业排列
(0,2,3,1)
(d)最优调度方案
p1p23689101542
例题:
下面是北大PKU POJ 第2751题Saving Endeavour
有2台机器,n件任务,必须先在S1上做,再在S2上做。任务之间先做后做任意。求最早的完工时间。
双机调度问题Johnson算法简析:
(1)把作业按工序加工时间分成两个子集,第一个集合中在S1上做的时间比在S2上少,其它的作业放到第二个集合。先完成第一个集合里面的作业,再完成第二个集合里的作业。
(2)对于第一个集合,其中的作业顺序是按在S1上的时间的不减排列;对于第二个集合,其中的作业顺序是按在S2上的时间的不增排列。
Johnson算法的时间取决于对作业集合的排序,因此,在最怀情况下算法的时间复杂度为0( nlogn ),所需的空间复杂度为0( 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);
}
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;
}