回溯法——批处理作业调度

问题描述:

  给定n个作业的集合J=(J1,J2,... ,Jn)。每一个作业Ji都有两项任务分别在2台机器上完成。每个作业必须先有机器1处理,然后再由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理时间。则所有作业在机器2上完成处理时间和f=F2i,称为该作业调度的完成时间和

简单描述:

  对于给定的n个作业,指定最佳作业调度方案,使其完成时间和达到最小

举例说明:

tji 机器1 机器2
作业1 2 1
作业2 3 1
作业3 2 3

  

  这3个作业的调度方案共有6种(即3个作业的全排列),分别是123,132,213,231,312,321,它们所相应的完成时间和分别是19,18,20,21,19,19。显而易见,最佳调度方案是132,其完成时间和为18。

算法设计:

  从n个作业中找出有最小完成时间和的作业调度,所以批处理作业调度问题的解空间是一棵排列树。按照回溯法搜索排列树的算法框架,设开始时x=[1,2, ... , n]是所给的n个作业,则相应的排列树由x[1:n]的所有排列构成。

  类Flowshop的数据成员记录解空间的结点信息,以便减少传给Backtrack的参数。二维数组M是输入作业的处理时间,bestf记录当前最小完成时间和,bestx记录相应的当前最佳作业调度。

  在递归函数Backtrack中,

    当i>n时,算法搜索至叶子结点,得到一个新的作业调度方案。此时算法适时更新当前最优值和相应的当前最佳调度。

    当i<n时,当前扩展结点位于排列树的第(i-1)层,此时算法选择下一个要安排的作业,以深度优先方式递归的对相应的子树进行搜索,对不满足上界约束的结点,则剪去相应的子树。

算法描述:

注:1、区分作业i和当前第i个正在执行的作业

      给x赋初值,即其中一种排列,如x=[1,3,2];M[x[j]][i]代表当前作业调度x排列中的第j个作业在第i台机器上的处理时间;如M[x[2]][1]就意味着作业3在机器1上的处理时间。

  2、bestf的初值

      此问题是得到最佳作业调度方案以便使其完成时间和达到最小,所以当前最优值bestf应该赋值为较大的一个值。

  3、f1、f2的定义与计算

      假定当前作业调度排列为:x=[1,2,3];f1[i]即第i个作业在机器1上的处理时间,f2[j]即第j个作业在机器2上的处理时间;则:

      f1[1]=M[1][1] , f2[1]=f1[1]+M[1][2]

      f1[2]=f1[1]+M[2][1] , f2[2]=MAX(f2[1],f1[2])+M[2][2] //f2[2]不光要等作业2自己在机器1上的处理时间,还要等作业1在机器2上的处理时间,选其大者。

      f1[3]=f1[2]+M[3][1] , f2[3]=MAX(f2[2],f1[3])+M[3][2]

    f1只有当前值有用,可以覆盖赋值,所以定义为int型变量即可,减少空间消耗;f2需要记录每个作业的处理时间,所以定义为int *型,以便计算得完成时间和。

  4、f2[0]的初值

      f2[i]的计算都是基于上一个作业f2[i-1]进行的,所以要记得给f2平[0]赋值为0。

 1 class Flowshop
 2 {
 3     friend Flow(int * *,int,int[]);
 4 private:
 5     void Backtrack(int i);
 6     int * * M,      //各作业所需的处理时间,根据上面的例子就是4*3的矩阵————M[j][i]代表第j个作业在第i台机器上的处理时间
 7         * x,       //当前作业调度————其中一种排列顺序
 8         * bestx,     //当前最优作业调度
 9         * f2,       //机器2完成处理时间————记录每个作业在机器2上的完成时间
10         f1,        //机器1完成处理时间————定义int型,减少空间消耗(因为只有当前的f1有用,所以可以覆盖赋值)
11         f,        //完成时间和
12         bestf,      //当前最优值
13         n;        //作业树
14 };
15 void Flowshop::Backtrack(int i)
16 {
17     if(i>n)
18     {
19         for(int j=1;j<=n;j++)
20             bestx[j] = x[j];
21         bestf = f;
22     }
23     else
24     {
25         for(int j=i;j<=n;j++)  //排列树中j从i开始————控制分支数
26         {
27             f1+=M[x[j]][i];  //在第1台机器上的完成处理时间————着重关注M矩阵的行标(代表当前执行的作业,是动态变化的)
28             f2[i]=((f2[i-1]>f1)?f2[i-1]:f1)+M[x[j]][2];  //在机器2上的完成处理时间,f2[0]初值赋为0
29             f+=f2[i];    //总的完成时间和
30             if(f<bestf)  //剪枝函数
31             {
32                 Swap(x[i],x[j]);
33                 Backtrack(i+1);
34                 Swap(x[i],x[j]);
35             }
36             f1 -= M[x[j]][1];  //改变机器完成时间计数————递归返回时
37             f -= f2[i];
38         }
39     }
40 }
41 int Flow(int * * M,int n,int bestx[])
42 {
43     int ub = INT_AMX;
44     Flowshop X;
45     X.x = new int [n+1];
46     X.f2 = new int [n+1];
47     X.M = M;
48     X.n = n;
49     X.bestf = ub;
50     X.bestx = bestx;
51     X.f1 = 0;
52     X.f = 0;
53     for(int i=0;i<=n;i++)
54     {
55         X.f2[i] = 0;
56         X.x[i] i;
57     }
58     X.Backtrack(1);
59     delete [] X x;
60     delete [] X f2;
61     return X.bestf;
62 }
时间: 2024-10-13 00:54:26

回溯法——批处理作业调度的相关文章

回溯法 -数据结构与算法

1.回溯法算法思想: 定义: 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”. 1.回溯法适用:有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法. 2.有组织的穷举式搜索:回溯法的基本做法是搜索或者有的组织穷尽搜索.它能避免搜索所有的可能性.即避免不必要的搜索.这种方

回溯法与分支限界

回溯法 1.有许多问题,当需要找出它的解集或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法. 2.回溯法的基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法.这种方法适用于解一些组合数相当大的问题. 3.回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树.算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解.如果肯定不包含(剪枝过程),则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯:否则,进入该子树,继续按深度优先策略搜索. 问

算法设计与分析——回溯法算法模板

以深度优先方式系统搜索问题解的算法称为回溯法.在回溯法中,解空间树主要分为了四种子集树.排列树.n叉树和不确定树. 在<算法设计与分析课本>中介绍了11个回溯法的问题样例,这里根据解空间树的类型做一个分类. 子集树 装载问题 符号三角形问题 0-1背包问题 最大团问题 算法模板: void backtrack(int t) { if(搜索到叶子结点) { return; } for(i=0; i<=1; i++) //01二叉树 { if(满足约束函数和限界函数)//剪枝 { backt

五大常用算法之四:回溯法

(转自:http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html) 1.概念 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径. 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”. 许

0-1背包-回溯法

算法描述: 0-1背包的回溯法,与装载问题的回溯法十分相似.在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树.当右子树中有可能包含最优解时才进入右子树进行搜索.否则将右子树剪去. 计算右子树上界的更好算法是: 将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包. 算法实现: 由Bound函数计算当前节点处的上界. 类Knap的数据成员记录解空间树的节点信息,以减少参数传递及递归调用所需的栈空间. 在解空间树的当前扩展结点处,仅当要进

回溯法浅谈

回溯法是初学者学习暴力法的第一个障碍,所谓回溯就是指当把问题分成若干步骤并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现象称为回溯.正是因为这个原因,递归枚举算法常被称为回溯法,应用十分普遍. 八皇后问题 1 int tot=0; 2 int c[maxn]; //c[x]表示x行所在的列数 3 void dfs(int n,int cur){ 4 if(cur==n) ++tot; 5 for(int i=0;i<n;i++){ 6 int flag=0; 7 c[c

回溯法求迷宫问题

回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”.本文使用回溯法求解迷宫问题迷宫问题,有一个m行n列的矩阵代表迷宫,1代表此路不通,0代表此路通.指定入口和出口,判断是否能从入口进,从出口走出.此程序只判断从路口到出口是否能走通,找到的路不一定是最短路(最短路的程序在下一篇中使用BFS算法给出),注意:从入口到

经典算法学习之回溯法

回溯法的应用范围:只要能把待求解的问题分成不太多的步骤,每个步骤又只有不太多的选择就可以考虑使用回溯法. 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束. 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束. 回溯法将问题的候选解按照某一顺序逐一枚举和检验.当发现当前候选解不可能是解时,就选择下一个候选解,若当前候选解符合要求,且还未达到求解的规模,则继续扩展当前候 选解的规模,如果候选解已经满足了所有要求,并且也达到了问题的规模,那么该候选解就是

回溯法

递归回溯 由于回溯法是对解空间的深度优先搜索,因此在一般情况下可用递归函数来实现回溯法如下: t表示递归深度,即当前扩展节点在解空间树的深度. n用来控制递归深度.当t>n时表示算法搜索到叶节点. void backtrack( int t ) { if ( t>n ) output(x); else for( int i=f(n,t); i<=g(n,t); i++ ) { x[t]=h(i); if ( constraint(t)&&bound(t) ) backtr