回溯法经典例题(四):java解批处理作业调度

批处理作业调度

问题描述

每一个作业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

代码实现

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
			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);
	}

}

你可能感兴趣的:(回溯法,算法)