流水作业调度——动态规划

问题描述:    

     n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。每个作业加工的顺序都是先在M1上加工,然后在M2上加工。M1和M2加工作业i所需的时间分别为ai和bi。流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。

问题分析:
 

若M1,M2加工作业i所需要的时间分别为ai和bi(1<=i<=n)

对于M1来说,n个作业无论以任何顺序加工,都是依次在M1上连续加工,无需等待,因此加工时间取决于作业本身的加工时间。。

对于M2来说,情况则有较大不同,由于作业要先在M1上加工,然后才能到M2,因此作业在M2上的加工时间受限于在M1和M2两个机器上加工时间的双重因素的影响。

在M2上的加工时间(包括等待时间)对总的加工时间有较大的的影响

所以这里主要讨论作业在M2上的加工情况:

分为两种情况

  1. 假设作业加工顺序为t(1),t(2)....t(n)

 

2.假设加工作业顺序为t(1),t(2)....t(n)

 

所以流水作业调度问题:就是要确定N个作业的最优加工顺序,使得M2上加工完成所需的时间最少==总的加工作业时间最短

 

 

上边两个特点:M1上加工时间短的先来,M2上加工时间长的先来实际上就满足了johnson法则的原理

可以证明得到:任意两个满足johnson法则的调度具有相同的加工时间,从而满足Johnson法则的调度均为最优调度。至此将流水作业调度问题转化为求满足johnson法则的调度问题。

johnson法则证明如下:借鉴博客原文链接:https://blog.csdn.net/liufeng_king/article/details/8678316

 

 

Johnson法则:实际含义——》一句话概括上方两个特点:尽可能早安排m1上加工时间<在M2上的加工时间的作业

在M1上加工时间短,将其放前边

在M2上加工时间短,将其放后边

 

于是我们就清楚流水作业调度把加工作业分为两类

  1. 在M1上加工时间<在M2上加工时间,并且按照在M1上加工时间由小到大(递增)排序
  2. 在M1上加工时间>=在M2上加工时间,并且按照在M2上加工时间由大到小(递减)排序

第一类作业第二类作业构成的顺序满足johnson法则的最优调度。

 

这里给出一个例子帮助更好的理解:

流水作业调度求解实例

求最佳作业安排次序及时间

作业

J1

J2

J3

J4

J5

J6

M1

30

120

50

20

90

110

M2

80

100

90

60

30

10

①把作业分成两类

N1={J1,J3,J4}--------------在M1上加工时间<在M2上加工时间

N1={J4,J1,J3}--------------按照在M1上加工时间由小到大(递增)排序

 

N2={J2,J5,J6}--------------在M1上加工时间>在M2上加工时间

N2={J2,J5,J6}--------------按照在M2上加工时间由大到小(递减)排序

②得到最优序列

N1接N2构成满足JOHNSON法则的最优序列:J4,J1,J3,J2,J5,J6

 

 

作业

J4

J1

J3

J2

J5

J6

M1

20

30

50

120

90

110

M2

60

80

90

100

30

10

 

 

③作业在M1和M2上的结束时间表

作业

J4

J1

J3

J2

J5

J6

M1

20

20+30=50

50+50=100

100+120=220

220+90=310

310+110=420

M2

20+60=80

80+80=160

160+90=250

250+100=350

350+30=380

420+10=430

 

 因此总的加工时间为430。

》其中J1-J5在M2上执行均无等待时间

》J6在M2上执行时:

由于J5在M2上的完成时间为380,此时J6仍在M1上执行,结束时间为420,所以M2等待了420-380=40于420时刻开始执行J6结束时间430,总时长430.

 

 代码:

#include<stdio.h>
#include<string.h>
#include<algorithm> 
#define N 100
using namespace std;

struct node {
    int time;//执行时间 
    int index;//作业序号
    bool group;//1代表第一个机器,0代表第二个机器 
};

bool cmp(node a,node b)
{//升序排序 
    return a.time<b.time; 
}
int main()
{
    int i,j,k,n;
    int M1[N]={0},M2[N]={0};
    int best[N];//最优调度序列 
    node c[N];
    printf("请输入作业的个数(<100)\n");
    scanf("%d",&n);
    printf("请分别输入每个作业在M1与M2上的作业时间:(以空格分隔,eg:30 80)\n");
    for(i=0;i<n;i++) {
        scanf("%d%d",&M1[i],&M2[i]);
    }
    for(i=0;i<n;i++) {  //把n个作业分成两组 
        c[i].time=M1[i]>M2[i]?M2[i]:M1[i];
        c[i].index=i;
        c[i].group=M1[i]<=M2[i];

    }
    //验证输出 
    printf("\n\n");
    for(i=0;i<n;i++)
    {
    	printf("%d %d %d\n",c[i].time,c[i].index,c[i].group);
	}
	
    sort(c,c+n,cmp);//按照c[]中作业时间增序排序
      //验证输出 
    printf("\n\n");
    for(i=0;i<n;i++)
    {
    	printf("%d %d %d\n",c[i].time,c[i].index,c[i].group);
	}
    j=0,k=n-1;
    for(i=0;i<n;i++) {
        if(c[i].group) { //M1.从i=0开始放入到best[]中 
            best[j++]=c[i].index;
        }
        else {
            best[k--]=c[i].index;//M2,倒着来 
        }
    }
    j=M1[best[0]];//初始化,M1最优调度序列下的作业结束时间 
    k=j+M2[best[0]];//初始化,M2最优调度序列下的作业结束时间 
    for(i=1;i<n;i++) {
        j+=M1[best[i]];//下一个作业在M1上的结束时间 
        if(j<k)//计算下一个作业在M2上的结束时间,如果j<k表明本作业在M1结束时间小于上一个作业的M2结束时间,就说这个作业在30完成了M1的工作,上一个作业在50完成M2的工作,就是说你得等,M2不空闲,这是好的情况 
        {
        	k=k+M2[best[i]];//那么本作业在M2上的结束时间就是上一个作业在M2上的结束时间加上我这个作业在M2上的运行时间 
		}else{
			k=j+M2[best[i]];//否则的话,就说明想要M2的时候,M2正好空着,那就在M1上的结束时间加上M2上的运行时间 
		}
      //  k=j<k?(k+M2[best[i]]):j+M2[best[i]];//消耗总时间的最大值 
    }
    printf("本次运行总时间为:\n");
    printf("%d\n",k);
    printf("最优调度序列为:\n");
    for(i=0;i<n;i++) {
        printf("%d ",best[i]+1); 
    }
    printf("\n");
    return 0;
} 


/*
测试样例
6
30 80
120 100
50 90
20 60
90 30
110 10
*/

 

  • 13
    点赞
  • 140
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值