问题描述:
n个作业{1,2,…,n},要在由机器M1和M2组成的流水线上完成加工。
每个作业加工的顺序都是先在M1上加工,然后在M2上加工。
要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。
问题分析:
直观上,一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。
在一般情况下,机器M2上会有机器空闲和作业积压两种情况。
设全部作业的集合为N={1,2,…,n}。S是N的作业子集。
通常,机器M1开始加工S中作业时,机器M2还在加工其它作业,要等时间t后才可利用。
将这种情况下完成S中作业所需的最短时间记为T(S, t)。
流水作业调度问题的最优值为T(N, 0)。
处理过程:
1. 将{a1,a2,…,an,b1,b2,…,bn}排成非递减序列;
2. 依次从序列中抽出最小元素m,如果m = aj且作业j还没有排入调度表,则把作业 j 安排在调度表可达的最左边一项空位上(设n个作业的调度表有n项,开始全部为空)。
3. 如果m = bj且作业j还没有排入调度表,则把作业j安排在调度表可达的最右边一项空位上。
4.如果作业j已排在调度表中,则取序列的下一个最小元素m,继续按上述方法调度,直到元素取完为止。
最后得到的调度表中的作业的顺序就是各作业的加工顺序。
例 设n = 4,
(a1,a2,a3,a4)=(3,4,8,10),
(b1,b2,b3,b4)=(6,2,9,15),
经排序后为
(b2,a1,a2,b1,a3,b3,a4,b4)=
(2,3,4,6,8,9,10,15)。
设σ1,σ2,σ3,σ4是最优调度。
因为最小数是b2,故置σ4= 2。下一个次小的数是a1,置σ1= 1。接下去是a2,作业2已经被调度。再其次是b1作业1也已经被调度。下一个是a3,置σ2= 3,依次置σ3= 4。
算法复杂度分析:
算法的主要计算时间花在对作业集的排序。因此,在最坏情况下算法所需的计算时间为O(nlogn)。所需的空间为O(n)。
代码实现:
#include<iostream> #include<algorithm> using namespace std; class Jobtype { public: int key; int index; bool job; int operator >(Jobtype a) const { return (key>a.key); } }; void Shellsort(Jobtype *a,int n) { for(int dk=n/2;dk>0;dk/=2) { for(int i=dk;i<n;i++) { for(int j=i-dk;j>=0 && a[j]>a[j+dk];j-=dk) { Jobtype t=a[j]; a[j]=a[j+dk]; a[j+dk]=t; } } } } int FlowShop(int n,int a[],int b[],int c[]) { Jobtype *d=new Jobtype [n]; for(int i=0;i<n;i++) { d[i].key=a[i]>b[i]?b[i]:a[i]; d[i].job=(a[i]<=b[i]); d[i].index=i; } Shellsort(d,n); for(int i=0;i<n;i++) { cout<<"# "<<d[i].index<<" "<<d[i].job <<endl; } int j=0,k=n-1; for(int i=0;i<n;i++) { if(d[i].job) { c[j++]=d[i].index; } else { c[k--]=d[i].index; } } for(int i=0;i<n;i++) cout<<"# "<<c[i]<<endl; int p=a[c[0]]; int q=j+b[c[0]]; for(int i=1;i<n;i++) { p+=a[c[i]]; q= p<q? q+b[c[i]]:p+b[c[i]]; } delete d; return q; } int main() { int n; int a[100],b[100],c[100]; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<n;i++) cin>>b[i]; int k=FlowShop(n,a,b,c); cout<<k; return 0; }样例及答案:
6
2 5 7 10 5 2
3 8 4 11 3 4
答案 15
5
2 4 3 6 1
5 2 3 1 7
答案 19