批处理作业调度
问题描述
每一个作业Ji都有两项任务分别在2台机器上完成。每个作业必须先有机器1处理,然后再由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理时间。则所有作业在机器2上完成处理时间和f=F2i,称为该作业调度的完成时间和。此时要找出最小的完成时间和
给出一个例子:
算法分析
根据问题描述可知,需要计算出每个作业在机器二完成的时间,计算例子如下(以下以作业调度为1.2.3为例)
由上图可知
作业1在机器2完成处理时间是3
作业2在机器2完成处理时间是6(要算上前面作业1在机器2处理时占用的时间)
作业2在机器2完成处理时间是10
因此完成时间和是19
从例子中可以看出需要变量m[][](各个作业在机器一机器二的处理时间),f1(机器一的处理时间),f2[i](第i个作业在机器二的处理时间),f(完成时间和),通过比较f1和f2[i-1],取其大加上该作业在机器二的处理时间成为f2[i]
定义解空间
各个作业的不同排列就是该题的解空间
例题的解空间为{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}
确定解空间结构
由例题可知,该解空间结构为排列数
剪枝函数
因为要找出最小的,所以在不可能出现最优解的时候即可进行剪枝,所以只需f<bestf即可
代码实现
package FlowShopProblem;
import java.util.Scanner;
public class FlowShop {
//以下涉及到数组的变量,第一个元素即第0个都是不会用到的,所以数组元素个数都需+1
int n;//作业个数
int f;//当前作业完成时间总和
int bestf;//当前最优完成时间和
int[] x;//当前作业调度
int[] bestx;//最优作业调度
int[][] m;//各个作业需要的时间
int f1;//机器一处理的时间
int[] f2;//机器二处理的时间
public FlowShop(int n,int[][] m){//完成数据的初始化
this.n=n;
this.m=m;
f1=0;
f=0;
bestf=10000;//给定初始值
bestx=new int[n+1];
x=new int[n+1];
//初始化,x[i]为原始排序
for(int i=1;i<=n;i++){
x[i]=i;
}
f2=new int[n+1];
}
//在Java中交换数组的两个元素下标位置不能直接进行交换
//要通过引用来交换,直接交换没有指向同个对象(数组)
private void swap(int[] x,int i, int j) {
int temp=x[i];
x[i]=x[j];
x[j]=temp;
}
public void backtrack(int t) {
if(t>n) {//此处不需要再次判别f<bestf,因为在进行backtrack(t+1)前就已经判别了
for(int i=1;i<=n;i++) {
bestx[i]=x[i];
}
bestf=f;
}
else {
for(int j=t;j<=n;j++) {
f1+=m[x[j]][1];
f2[t]=((f2[t-1]>f1)? f2[t-1]:f1)+m[x[j]][2];//特别注意在当t=1时,f2[t-1]需赋值为0,这也是为什么不从第一个元素记录实际数据
f+=f2[t];
if(f<bestf) {
swap(x,t,j);
backtrack(t+1);
swap(x,t,j);
}
f1-=m[x[j]][1];
f-=f2[t];
}
}
}
public static void main(String[] args) {
System.out.println("请输入作业个数:");
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[][] m= new int[n+1][3];//m的下标从1开始,因此第一行的0和每一行第一列的0无用
System.out.println("请输入作业在机器一和机器二的处理时间\n(第一行全输入0,每一行第一列输入0)");
for(int i=0;i<m.length;i++)
for(int j=0;j<3;j++)
m[i][j]=sc.nextInt();
FlowShop f=new FlowShop(n,m);
f.backtrack(1);
System.out.println("最优批处理作业调度顺序为:");
for(int i=1;i<=n;i++)
System.out.print(f.bestx[i]+" ");
System.out.println();
System.out.println("最优调度所需的最短时间为:\n"+f.bestf);
}
}