双机流水作业调度问题的Johnson算法
n个作业要在由两台机器M1和M2组成的流水线上完成加工. 每个作业i必须先在M1上然后在M2上加工, 时间分别为ai和bi
确定这n个作业的加工顺序, 使得从第一个任务开始在M1上加工到最后一个任务在M2上加工完成的总时间尽量小
Johnson算法.
设N1为a<b的作业集合, N2为a>=b的作业集合, 将N1的作业按a非减序排序, N2中的作业按照b非增序排序, 则N1作业接N2作业构成最优顺序.(证明略)
2008-12-27 00:53
求解流水作业调度问题的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)所示。
(2) 对三元组表按处理时间排序,得到排序后的三元组表d。如图(b)所示。
(3) 对三元组表的每一项d(i)(0<=i<n),从左右两端生成最优作业排列c[j](0<=j<n),c[j]是作业号。如果d[i]设备号为1,则将作业i置于c的左端末尾,否则置于c的右端末尾。如图(c)所示,由两端想中间存放。
作业号 处理时间 设备号
0 0 3 0
1 1 2 1
2 2 8 0
3 3 10 0
(a)三元组表
作业号 处理时间 设备号
0 1 2 1
1 0 3 0
2 2 8 0
3 3 10 0
(b)按处理时间排序
(0, 2, 3, 1)
(c)最优作业排列
P1 3 8 10 4
P2 6 9 15 2
(d)最优调度方案
程序是流水作业调度的Johnson算法。
Johnson算法
#include<iostream>
#include<algorithm>
using namespace std;
struct Triplet{ //三元组结构
int operator<(const Triplet & b)const {return t <b.t;}
int jobNo,t,ab; //jobNo为作业,体委处理时间,ab为设备号
};
void FlowShop(int n,int *a,int*b,int*c)
{
Triplet d[n];
for(int i=0;i<n;i++) //算法步骤(1),生成三元组表d
if (a[i]<b[i])
{
d[i].jobNo=i;d[i].ab=0;d[i].t=a[i];
}
else
{
d[i].jobNo=i;d[i].ab=1;d[i].t=b[i];
}
sort(d,d+n);//算法步骤(2),排序
int left=0,right=n-1;
for(int i=0;i<n;i++) //算法步骤(3),生成最优解
if (d[i].ab==0) c[left++]=d[i].jobNo;
else c[right--]=d[i].jobNo;
}
int main()
{
int a[4]={3,4,8,10};
int b[4]={6,2,9,15};
int c[4];
FlowShop(4,a,b,c);
for(int i=0;i<4;++i)
cout<<c[i]<<" ";
cout<<endl;
system("pause");
return 0;
}
Johnson算法的时间取决于对作业集合的排序,因此,在最怀情况下算法的时间复杂度为O(nlogn),所需的空间复杂度为O(n).
北大PKU POJ 2751 Saving Endeavour问题就是2台机器,n件任务,必须先在S1上做,再在S2上做。任务之间先做后做任意。求最早的完工时间。
这是一个经典问题:2台机器的情况下有多项式算法(Johnson算法),3台或以上的机器是NP-hard的。思想就是贪心,时间复杂度是O(nlogn) 。
Johnson算法
(1)把作业按工序加工时间分成两个子集,第一个集合中在S1上做的时间比在S2上少,其它的作业放到第二个集合。先完成第一个集合里面的作业,再完成第二个集合里的作业。
(2)对于第一个集合,其中的作业顺序是按在S1上的时间的不减排列;对于第二个集合,其中的作业顺序是按在S2上的时间的不增排列。
My Code:
/*
双机调度问题Johnson算法:
(1) 把作业按工序加工时间分成两个子集,第一个集合中在S1上做的时间比在S2上少,
其它的作业放到第二个集合。先完成第一个集合里面的作业,再完成第二个集合
里的作业。
(2) 对于第一个集合,其中的作业顺序是按在S1上的时间的不减排列;对于第二个集
合,其中的作业顺序是按在S2上的时间的不增排列。
*/ 复制内容到剪贴板 代码:#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;
}