问题描述:给定n个作业的集合{J1,J2,…,Jn}。每个作业必须先由机器1处理,然后由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和。
批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小
分析:这3个作业的6种可能的调度方案是1,2,3;1,3,2;2,1,3;2,3,1;3,1,2;3,2,1;它们所相应的完成时间和分别是19,18,20,21,19,19。易见,最佳调度方案是1,3,2,其完成时间和为18。
以3,1,2顺序为例:
算法实现步骤
1.if
(当前层大于总数) 遍历到排序树的叶节点
2.else
遍历到排序树的第k层节点
—①先向下一层子节点探索
—-if
(若当前完成时间和小于当前最优值) 则递归到下一层节点
—②回溯到父节点
public class test5_3 {
static int n = 3, //作业数 (需初始化)
f = 0, //完成时间和
f1 = 0, //机器1完成处理时间
bestf = Integer.MAX_VALUE; //当前最优值 (需初始化最大值)
static int[][] m = {{0,0,0} //各作业所需的处理时间 (需初始化)
,{0,2,1}
,{0,3,1}
,{0,2,3}};
static int[] x = {0,1,2,3}; //当前作业调度 (需初始化)
static int[] bestx = new int[n+1]; //当前最优作业调度
static int[] f2 = new int[n+1]; //机器2完成处理时间
/**
* 回溯法
* @param k 表示遍历的排序树的层数,初始k=1,表示从第一层根节点开始
*/
private static void backtrack(int k){
//1.遍历到排序树的叶节点
if(k>n){
for(int i=1;i<=n;i++)
bestx[i] = x[i];
bestf = f;
}else
//2.遍历到排序树的第k层节点 k∈[1:n]
for(int i=k;i<=n;i++){ //排列树下此for循环抽象成广度优先搜索,即从k节点下的(n-k)个子分支依次遍历
//*****2.1先向下一层子节点探索****(值的探索)******************
f1 += m[x[i]][1];
f2[k] = ((f2[k-1]>f1)? f2[k-1]:f1) + m[x[i]][2];
f += f2[k];
//*****2.1先向下一层子节点探索*****(值的探索)*****************
//*****2.2若当前完成时间和小于当前最优值,则递归到下一层节点********
if(f<bestf){
swap(x,k,i);//类别全排列算法(节点的真正探索)
backtrack(k+1); //抽象成深度优先搜索,即递归到下一层节点
swap(x,k,i);//类别全排列算法(节点的真正回溯)
}
//*****2.2若当前完成时间和小于当前最优值,则递归到下一层节点********
//*****2.3回溯到父节点***********(值的回溯)*****************
f1 -= m[x[i]][1];
f -= f2[k];
//*****2.3回溯到父节点***********(值的回溯)****************
}
}
private static void swap(int[] x,int i,int j){
int temp;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
public static void main(String[] args) {
backtrack(1);
System.out.println("最优调度下完成时间和为:"+bestf);
System.out.print("最优作业调度顺序如下:");
for(int i=1;i<=n;i++)
System.out.print(bestx[i]+" ");
}
}
运行结果如下:
最优调度下完成时间和为:18
最优作业调度顺序如下:1 3 2
总结:最坏情况下,整个算法的时间复杂度为O(n!)。