【算法学习笔记十二】回溯法(二)

回溯法(一)

应用分支限界法的关键问题

如何确定合适的限界函数

        常见方法是先对整个问题估计出下界(最小化问题)或上界(最大化问题),而限界函数是在部分解的基础上对剩余的未知部分进行界的重新估计

如何组织待处理结点表

如何确定最优解中的各个分量   

       分支限界法对问题的解空间树中结点的处理是跳跃式的,回溯也不是单纯地沿着双亲结点一层一层向上回溯,因此,当搜索到某个叶子结点且该叶子结点的目标函数值在表PT中最大时(假设求解最大化问题),求得了问题的最优值,但是,却无法求得该叶子结点对应的最优解中的各个分量。这个问题可以用如下方法解决:

        –对每个扩展结点保存该结点到根结点的路径;

        –在搜索过程中构建搜索经过的树结构,在求得最优解时,从叶子结点不断回溯到根结点,以确定最优解中的各个分量

例如0/1揹包问题,为了对每个扩展结点保存该结点到根结点的路径,将部分解(x1, …, xi)和该部分解的目标函数值都存储在待处理结点表PT中,在搜索过程中表PT的状态如图所示。

对0/1揹包问题,为了在搜索过程中构建搜索经过的树结构,设一个表ST,在表PT中取出最优值结点进行扩充时,将最优值结点存储到表ST中,表PT和表ST的数据结构为(物品i-1的选择结果,<物品i, 物品i的选择结果>ub),在搜索过程中表PT和表ST的状态如下所示。 

分支限界法的时间性能

分支限界法和回溯法实际上都属于蛮力穷举法,当然不能指望它有很好的最坏时间复杂性,遍历具有指数阶个结点的解空间树,在最坏情况下,时间复杂性肯定为指数阶。

与回溯法不同的是,分支限界法首先扩展解空间树中的上层结点,并采用限界函数,有利于实行大范围剪枝,同时,根据限界函数不断调整搜索方向,选择最有可能取得最优解的子树优先进行搜索。所以,如果选择了结点的合理扩展顺序以及设计了一个好的限界函数,分支界限法可以快速得到问题的解。

分支限界法的较高效率是以付出一定代价为基础的:

–一个更好的限界函数通常需要花费更多的时间计算相应的目标函数值,而且对于具体的问题实例,通常需要进行大量实验,才能确定一个好的限界函数;

–由于分支限界法对解空间树中结点的处理是跳跃式的,因此,在搜索到某个叶子结点得到最优值时,为了从该叶子结点求出对应的最优解中的各个分量,需要对每个扩展结点保存该结点到根结点的路径,或者在搜索过程中构建搜索经过的树结构,这使得算法的设计较为复杂;

–算法要维护一个待处理结点表PT,并且需要在表PT中快速查找取得极值的结点,等等。这都需要较大的存储空间,在最坏情况下,分支限界法需要的空间复杂性是指数阶。

TSP问题:

TSP问题是指要访问n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。

采用贪心法求得近似解为1→3→5→4→2→1,其路径长度为1+2+3+7+3=16,这可以作为TSP问题的上界。

把矩阵中每一行最小的元素相加,可以得到一个简单的下界,其路径长度为1+3+1+3+2=10,但是还有一个信息量更大的下界:考虑一个TSP问题的完整解,在每条路径上,每个城市都有两条邻接边,一条是进入这个城市的,另一条是离开这个城市的,那么,如果把矩阵中每一行最小的两个元素相加再除以2,如果图中所有的代价都是整数,再对这个结果向上取整,就得到了一个合理的下界。

lb=((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14

于是,得到了目标函数的界[14, 16]。

需要强调的是,这个解并不是一个合法的选择(可能没有构成哈密顿回路),它仅仅给出了一个参考下界。

 c表示已得的合法解

例如图示无向图,如果部分解包含边(1, 4),则该部分解的下界是lb=(5*2+(1+3)+((3+6)+(1+2)+(2+3)))/2=16。

或者: lb=((1+5)+(5+3)+((3+6)+(1+2)+(2+3)))/2=16(按上述进入和离开城市的方式计算)

搜索过程:

(1)在根结点1,根据限界函数计算目标函数的值为lb=((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14;

(2)在结点2,从城市1到城市2,路径长度为3,目标函数的值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点2加入待处理结点表PT中;在结点3,从城市1到城市3,路径长度为1,目标函数的值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点3加入表PT中;在结点4,从城市1到城市4,路径长度为5,目标函数的值为((1+5)+(3+6)+(1+2)+(3+5)+(2+3))/2=16,将结点4加入表PT中;在结点5,从城市1到城市5,路径长度为8,目标函数的值为((1+8)+(3+6)+(1+2)+(3+5)+(2+8))/2=19,超出目标函数的界,将结点5丢弃;

(3)在表PT中选取目标函数值极小的结点2优先进行搜索;

(4)在结点6,从城市2到城市3,目标函数值为((1+3)+(3+6)+(1+6)+(3+4)+(2+3))/2=16,将结点6加入表PT中;在结点7,从城市2到城市4,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,将结点7加入表PT中;在结点8,从城市2到城市5,目标函数值为((1+3)+(3+9)+(1+2)+(3+4)+(2+9))/2=19,超出目标函数的界,将结点8丢弃;

(5)在表PT中选取目标函数值极小的结点3优先进行搜索;

(6)在结点9,从城市3到城市2,目标函数值为((1+3)+(3+6)+(1+6)+(3+4)+(2+3))/2=16,将结点9加入表PT中;在结点10,从城市3到城市4,目标函数值为((1+3)+(3+6)+(1+4)+(3+4)+(2+3))/2=15,将结点10加入表PT中;在结点11,从城市3到城市5,目标函数值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点11加入表PT中;

(7)在表PT中选取目标函数值极小的结点11优先进行搜索;

(8)在结点12,从城市5到城市2,目标函数值为((1+3)+(3+9)+(1+2)+(3+4)+(2+9))/2=19,超出目标函数的界,将结点12丢弃;在结点13,从城市5到城市4,目标函数值为((1+3)+(3+6)+(1+2)+(3+4)+(2+3))/2=14,将结点13加入表PT中;

(9)在表PT中选取目标函数值极小的结点13优先进行搜索;

(10)在结点14,从城市4到城市2,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,最后从城市2回到城市1,目标函数值为((1+3)+(3+7)+(1+2)+(3+7)+(2+3))/2=16,由于结点14为叶子结点,得到一个可行解,其路径长度为16;

(11)在表PT中选取目标函数值极小的结点10优先进行搜索;

(12)在结点15,从城市4到城市2,目标函数的值为((1+3)+(3+7)+(1+4)+(7+4)+(2+3))/2=18,超出目标函数的界,将结点15丢弃;在结点16,从城市4到城市5,目标函数值为((1+3)+(3+6)+(1+4)+(3+4)+(2+3))/2=15,将结点16加入表PT中;

(13)在表PT中选取目标函数值极小的结点16优先进行搜索;

(14)在结点17,从城市5到城市2,目标函数的值为((1+3)+(3+9)+(1+4)+(3+4)+(9+3))/2=20,超出目标函数的界,将结点17丢弃;

(15)表PT中目标函数值均为16,且有一个是叶子结点14,所以,结点14对应的解1→3→5→4→2→1即是TSP问题的最优解,搜索过程结束。

    1.根据限界函数计算目标函数的下界down;采用贪心法得到上界up;
    2.将待处理结点表PT初始化为空;
    3.for (i=1; i<=n; i++)
             x[i]=0;
    4.k=1; x[1]=1;  //从顶点1出发求解TSP问题
    5.while (k>=1)
          5.1 i=k+1;
          5.2 x[i]=1;
          5.3 while (x[i]<=n)
               5.3.1 如果路径上顶点不重复,则
                       5.3.1.1 计算目标函数值lb;
                       5.3.1.2 if (lb<=up) 将路径上的顶点和lb值存储在表PT中;
               5.3.2 x[i]=x[i]+1;
         5.4 若i=n且叶子结点的目标函数值在表PT中最小
               则将该叶子结点对应的最优解输出;
         5.5否则,若i=n,则在表PT中取叶子结点的目标函数值最小的结点lb,
               令up=lb,将表PT中目标函数值lb超出up的结点删除;
         5.6 k=表PT中lb最小的路径上顶点个数;

多段图的最短路径问题

设图G=(V, E)是一个带权有向连通图,如果把顶点集合V划分成k个互不相交的子集Vi(2≤kn, 1≤ik),使得E中的任何一条边(u, v),必有uVivVi+m(1≤ik, 1<i+mk),则称图G为多段图,称sV1为源点,tVk为终点。

多段图的最短路径问题是求从源点到终点的最小代价路径。

对图示多段图求得近似解为0→2→5→8→9,其路径代价为2+7+6+3=18,这可以作为多段图最短路径问题的上界。把每一段最小的代价相加,可以得到一个非常简单的下界,其路径长度为2+4+5+3=14。于是,得到了目标函数的界[14, 18]。

由于多段图将顶点划分为k个互不相交的子集,所以,多段图划分为k段,一旦某条路径的一些段被确定后,就可以并入这些信息并计算部分解的目标函数值的下界。一般情况下,对于一个正在生成的路径,假设已经确定了i段(1≤ik),其路径为(r1, r2, …, ri, ri+1),此时,该部分解的目标函数值的计算方法即限界函数如下:

 搜索过程:

(1)在根结点1,根据限界函数计算目标函数的值为18;

(2)在结点2,第1段选择边<0, 1>,目标函数值为lb=4+8+5+3=20,超出目标函数的界,将结点2丢弃;在结点3,第1段选择边<0, 2>,目标函数值为lb=2+6+5+3=16,将结点3加入待处理结点表PT中;在结点4,第1段选择边<0, 3>,目标函数值为lb=3+4+5+3=15,将结点4加入表PT中;

(3)在表PT中选取目标函数值极小的结点4优先进行搜索;

(4)在结点5,第2段选择边<3, 5>,目标函数值为lb=3+4+6+3=16,将结点5加入表PT中;在结点6,第2段选择边<3, 6>,目标函数值为lb=3+7+5+3=18,将结点6加入表PT中;

(5)在表PT中选取目标函数值极小的结点3优先进行搜索;

(6)在结点7,第2段选择边<2, 4>,目标函数值为lb=2+6+5+3=16,将结点7加入表PT中;在结点8,第2段选择边<2, 5>,目标函数值为lb=2+7+6+3=18,将结点8加入表PT中;在结点9,第2段选择边<2, 6>,目标函数值为lb=2+8+5+3=18,将结点9加入表PT中;

(7)在表PT中选取目标函数值极小的结点5优先进行搜索;

(8)在结点10,第3段选择边<5, 7>,可直接确定第4段的边<7, 9>,目标函数值为lb=3+4+8+7=22,为一个可行解但超出目标函数的界,将其丢弃;在结点11,第3段选择边<5, 8>,可直接确定第4段的边<8, 9>,目标函数值为lb=3+4+6+3=16,为一个较好的可行解。由于结点11是叶子结点,并且其目标函数值是表PT中最小的,所以,结点11代表的解即是问题的最优解,搜索过程结束。

   1.根据限界函数计算目标函数的下界down;采用贪心法得到上界up;
   2.将待处理结点表PT初始化为空;
   3.for (i=1; i<=k; i++)
             x[i]=0;
   4.i=1; u=0;       //求解第i段
   5.while (i>=1)
         5.1 对顶点u的所有邻接点v
               5.1.1 计算目标函数值lb;
               5.1.2 若lb<=up,则将i,<u,v>,lb存储在表PT中;
         5.2 如果i= =k-1且叶子结点的lb值在表PT中最小,
               则输出该叶子结点对应的最优解;
         5.3 否则,如果i= =k-1且表PT中的叶子结点的lb值不是最小,则
               5.3.1 up=表PT中的叶子结点最小的lb值;
               5.3.2 将表PT中目标函数值超出up的结点删除;
         5.4  u=表PT中lb最小的结点的v值;
         5.5  i=表PT中lb最小的结点的i值;i++;

任务分配问题:

任务分配问题要求把n项任务分配给n个人,每个人完成每项任务的成本不同,要求分配总成本最小的最优分配方案。图示是一个任务分配的成本矩阵。

考虑任意一个可行解,例如矩阵中的对角线是一个合法的选择,表示将任务1分配给人员a、任务2分配给人员b、任务3分配给人员c、任务4分配给人员d,其成本是9+4+1+4=18;或者应用贪心法求得一个近似解:将任务2分配给人员a、任务3分配给人员b、任务1分配给人员c、任务4分配给人员d,其成本是2+3+5+4=14。显然,14是一个更好的上界。

为了获得下界,考虑人员a执行所有任务的最小代价是2,人员b执行所有任务的最小代价是3,人员c执行所有任务的最小代价是1,人员d执行所有任务的最小代价是4。因此,将每一行的最小元素加起来就得到解的下界,其成本是2+3+1+4=10。需要强调的是,这个解并不是一个合法的选择(3和1来自于矩阵的同一列),它仅仅给出了一个参考下界,这样,最优值一定是[10, 14]之间的某个值。

设当前已对人员1~i分配了任务,并且获得了成本v,则限界函数可以定义为:

 搜索过程:

(1)在根结点1,没有分配任务,根据限界函数估算目标函数值为2+3+1+4=10;

(2)在结点2,将任务1分配给人员a,获得的成本为9,目标函数值为9 + (3+1+4)=17,超出目标函数的界[10, 14],将结点2丢弃;在结点3,将任务2分配给人员a,获得的成本为2,目标函数值为2 + (3+1+4)=10,将结点3加入待处理结点表PT中;在结点4,将任务3分配给人员a,获得的成本为7,目标函数值为7 + (3+1+4)=15,超出目标函数的界[10, 14],将结点4丢弃;在结点5,将任务4分配给人员a,获得的成本为8,目标函数值为8 + (3+1+4)=16,超出目标函数的界[10, 14],将结点5丢弃;

(3)在表PT中选取目标函数值极小的结点3优先进行搜索;

(4)在结点6,将任务1分配给人员b,获得的成本为2+6=8,目标函数值为8+(1+4)=13,将结点6加入表PT中;在结点7,将任务3分配给人员b,获得的成本为2+3=5,目标函数值为5+(1+4)=10,将结点7加入表PT中;在结点8。将任务4分配给人员b,获得的成本为2+7=9,目标函数值为9+(1+4)=14,将结点8加入表PT中;

(5)在表PT中选取目标函数值极小的结点7优先进行搜索;

(6)在结点9,将任务1分配给人员c,获得的成本为5+5=10,目标函数值为10+4=14,将结点9加入表PT中;在结点10,将任务4分配给人员c,获得的成本为5+8=13,目标函数值为13+4=17,超出目标函数的界[10, 14],将结点10丢弃;

(7)在表PT中选取目标函数值极小的结点6优先进行搜索;

(8)在结点11,将任务3分配给人员c,获得的成本为8+1=9,目标函数值为9+4=13,将结点11加入表PT中;在结点12,将任务4分配给人员c,获得的成本为8+8=16,目标函数值为16+4=20,超出目标函数的界[10, 14],将结点12丢弃;

(9)在表PT中选取目标函数值极小的结点11优先进行搜索;

(10)在结点13,将任务4分配给人员d,获得的成本为9+4=13,目标函数值为13,由于结点13是叶子结点,同时结点13的目标函数值是表PT中的极小值,所以,结点13对应的解即是问题的最优解,搜索结束。

    1.根据限界函数计算目标函数的下界down;采用贪心法得到上界up;
    2.将待处理结点表PT初始化为空;
    3.for (i=1; i<=n; i++)
             x[i]=0;
    4.k=1; i=0;      //为第k个人分配任务,i为第k-1个人分配的任务
    5.while (k>=1)
          5.1 x[k]=1;
          5.2 while (x[k]<=n)
                5.2.1 如果人员k分配任务x[k]不发生冲突,则
                        5.2.1.1 计算目标函数值lb;
                        5.2.1.2 若lb<=up,则将i,<x[k], k>lb存储在表PT中;
                5.2.2 x[k]=x[k]+1;
          5.3 如果k= =n且叶子结点的lb值在表PT中最小,
                则输出该叶子结点对应的最优解;
          5.4 否则,如果k= =n且表PT中的叶子结点的lb值不是最小,则
                5.4.1 up=表PT中的叶子结点最小的lb值;
                5.4.2 将表PT中超出目标函数界的结点删除;
          5.5  i=表PT中lb最小的结点的x[k]值;
          5.6  k=表PT中lb最小的结点的k值;k++;

批处理作业调度问题

给定n个作业的集合J={J1, J2, …, Jn},每个作业都有3项任务分别在3台机器上完成,作业Ji需要机器j的处理时间为tij(1≤in, 1≤j≤3),每个作业必须先由机器1处理,再由机器2处理,最后由机器3处理。批处理作业调度问题要求确定这n个作业的最优处理顺序,使得从第1个作业在机器1上处理开始,到最后一个作业在机器3上处理结束所需的时间最少。

显然,批处理作业的一个最优调度应使机器1没有空闲时间,且机器2和机器3的空闲时间最小。可以证明,存在一个最优作业调度使得在机器1、机器2和机器3上作业以相同次序完成。

J={J1, J2, J3, J4}是4个待处理的作业,每个作业的处理顺序相同,即先在机器1上处理,然后在机器2上处理,最后在机器3上处理,需要的处理时间如图所示。

 若处理顺序为(J2, J3, J1, J4),则从作业2在机器1处理开始到作业4在机器3处理完成的调度方案如图所示。

 考虑理想情况,机器1和机器2无空闲,最后处理的恰好是在机器3上处理时间最短的作业。例如,以作业Ji开始的处理顺序,估算处理所需的最短时间是:t_{i1}+\sum_{j=1}^{n}t_{j2}+min\{t_{k3}\}

一般情况下,对于一个已安排的作业集合Mㄈ{1, 2, …, n},|M|=k,即已安排了k个作业,设sum1[k]表示机器1完成k个作业的处理时间,sum2[k]表示机器2完成k个作业的处理时间,现在要处理作业k+1,此时,该部分解的目标函数值的下界计算方法如下:

搜索过程:

(1)在根结点,将sum1[0]和sum2[0]分别初始化为0; 

(2)在结点2,以作业J1开始处理,则sum1[1]=5,目标函数值为5+(7+5+9+8)+2=36,sum2[1]=5+7=12,将结点2加入待处理结点表PT中;在结点3,以作业J2开始处理, 则sum1[1]=10,目标函数值为10+(7+5+9+8)+5=44,sum2[1]=10+2=12,将结点3加入表PT中;在结点4,以作业J3开始处理,则sum1[1]=9,目标函数值为9+(7+5+9+8)+2=40,sum2[1]=9+9=18,将结点4加入表PT中;在结点5,以作业J4开始处理,则sum1[1]=7,目标函数值为7+(7+5+9+8)+2=38,sum2[1]=7+8=15,将结点5加入表PT中;

(3)在表PT中选取目标函数值极小的结点2优先进行搜索;

(4)在结点6,准备处理作业J2,则sum1[2]=5+10=15,目标函数值为15+(5+9+8)+5=42,sum2[2]=15+5=20,将结点6加入表PT中;在结点7,准备处理作业J3,则sum1[2]=5+9=14,目标函数值为14+(5+9+8)+2=38,sum2[2]=14+9=22,将结点7加入表PT中;在结点8,准备处理作业J4,则sum1[2]=5+7=12,目标函数值为12+(5+9+8)+2=36,sum2[2]=12+8=20,将结点8加入表PT中;

(5)在表PT中选取目标函数值极小的结点8优先进行搜索;

(6)在结点9,准备处理作业J2,则sum1[3]=12+10=22,目标函数值为22+(5+9)+5=41,sum2[3]=22+5=27,将结点9加入表PT中;在结点10,准备处理作业J3,则sum1[3]=12+9=21,目标函数值为21+(5+9)+2=37,sum2[3]=21+9=30,将结点10加入表PT中;

(7)在表PT中选取目标函数值极小的结点10优先进行搜索;

(8)在结点11,准备处理作业J2,则sum1[4]=21+10=31,目标函数值为31+5=36,sum2[4]=31+5=36,由于结点11是叶子结点,并且目标函数值在表PT中最小,则结点11代表的解即是问题的最优解,sum2[4]是机器2完成所有4个作业的时间,则机器3完成所有4个作业的时间是sum2[4]+t23=36+2=38。搜索过程结束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章