【算法】分支限界法

一、概述

分支限界法是按照广度优先的策略搜索问题的解空间树,在搜索的过程中,对待处理的节点根据限界函数估算目标函数的可能的取值,从中选取使得目标函数可以取得最优的结点优先进行广度优先搜索,从而不断的调整搜索方向,尽快地找到问题的解。

1.1 设计思想

回溯法是使用深度优先的策略遍历解空间树的,如果某节点不满足约束条件则进行剪枝;而分支限界法首先要确定一个合理的限界函数,并且根据限界函数确定目标函数的界限,然后按照广度优先的策略搜索问题解空间树。在分支节点上依次扩展该节点的所有孩子节点,估算这些孩子节点目标函数可能的取值,如果某个孩子节点的目标函数可能取超过目标函数的界,那么则将其丢弃,因为该节点生成的解不可能比目前已有的最优解更好;否则,则将其加入待处理节点表PT中。依次从表PT中取出能够使目标函数取得最优值的结点成为当前的扩展节点,重复上述过程直到找到最优解。这点是比回溯法优秀的一点,因为分支限界法每次会优先使用最有可能得到最优解的结点,而不是和回溯一样的无脑的遍历。

分支限界法的关键问题如下:
1.如何确定合适的限界函数,限界函数要求计算简单,并且要求将最优解保留在解空间树中,尽可能早地将超出目标函数界限的结点进行剪枝,这对分支限界法的性能至关重要。
2.如何组织处理节点表。为了能够在待处理节点表PT中高效选出使得目标函数取得最优值的节点,可以使用堆或者优先队列的形式组织PT表
3.如何确定最优解的各个分量。分支限界法跳跃式处理空间树中的分量,而搜索到叶子结点的时候,虽然得出了问题最优解,但是路径信息由于跳跃式搜索丢失了,因此需要专门的数据结构用于记录路径信息。

二、图中的分支限界法

2.1 TSP问题

问题描述:
TSP问题指的是旅行家要从起始城市出发旅行n个城市,要求每个城市只经过一次之后然后回到出发的城市,并且要求路径最短。

想法:
首先我们需要确定TSP问题的目标函数的上下界,TSP问题的上界可以使用贪心算法得出,也就是从某城市出发,贪心地选择距离最短的路径,而TSP问题的下界,则只需要将图的邻接矩阵中每一行的最小的两个元素相加再除以2,因为在TSP问题中我们会从一条边进入一个顶点,又从另外一条边离开这个顶点,因此我们可以选择每行最小的两个元素作为下界,但是如果全部相加会导致一条路径走两次,因此除以二。

首先,我们会计算出下界,然后从起始顶点出发,查看和起始顶点临接的若干个顶点,并且计算目标函数值,如果目标函数值大于上界,那么证明经过该顶点一定无法得出最优解,那么则舍弃,也就是进行剪枝。如果目标函数值小于等于上界,那么则将它和他的函数值加入到表PT中。接着就是下一轮搜索,从PT表中找出目标函数值最小的节点进行下一轮计算,遍历它的孩子节点,将函数值小于上界的再次加入到PT表中。重复上述的操作,直到分支限界法的解空间树被遍历到了第n层,也就是存在一条已经经过了n个城市的路径,那么该路径就是最短路径,算法结束。如果想要求得最优解的各个分量,那么从叶子结点开始向父节点进行回溯。

2.2 多段图最短路径问题

设G是一个带权有向连通图,如果把顶点集合V划分为k个不相交的子集Vi,使得E中的任何一条边,都有u属于Vi,v属于Vi+m,则称该图为多段图。多段图最短路径问题求解的是从源点到终点的最小代价路径。

算法思想:
首先我们可以确定目标函数的上下界。使用贪心法可以确定函数的上界,也就是从源点出发,每次都选择路径最短的边。而将每一段的最小代价相加就可以得出一个下界,最短路径不可能比这个还小。首先,我们从起始顶点出发,遍历和顶点相连的各个顶点,然后计算它们的目标函数值,如果目标函数小于上界,那么就将该节点加入表PT中。接着我们在PT表中选择目标函数最小的节点,并且遍历和该节点相邻的结点,计算它们的目标函数,再次将目标函数小于上界的放入到PT表中。重复上述步骤直到遍历到了终点节点,或者解空间树中遍历到了叶子结点。那么此时该路径长度就是最短路径长度,使用回溯即可获得经过最短路径。

三、组合问题中的分支限界法

3.1 0-1背包问题

问题:
给定n种物品和一个容量为w的背包,物品i的重量为wi,其价值是vi,请问如何选择装入背包的物品,可以使得背包的价值最大

想法:
假设n种物品已经按照单位价格由大到小排序,那么使用贪心法可以求得问题的一个下界,也就是价值最大的可能的最小值。那么如何求被包的上界呢?那么我们可以使用性价比最高的物品完全填满整个背包,这就是背包可能达到的最大价值,这就是函数的上界。结社已经对前i个物品进行了某种特定的选择,那么计算节点目标函数上界的一个简单方法是将背包的剩余容量全部装入剩余物品中性价比最高的物品。
接下来是详细处理过程:
01背包问题的解空间树是一颗二叉树,其中第i层的左节点表示将物品i装入背包,右节点表示不装入背包。在根节点,没有任何物品被装入背包,因此背包的重量和价值都是0,可以计算得出当前节点的目标函数值,并且将根节点加入到节点表PT中。接着依次处理根节点的每一个孩子节点。计算孩子节点的背包价值和重量,如果重量不超过背包承载能力则将他们放入到PT表中。重复上述操作,每次都从背包中取出目标函数值最大的节点进行处理,直到将所有物品的情况都考虑过,或者说遍历到了解空间树的叶子结点,则可以得出一个可行解。从叶子结点回溯到根节点就可以得出其装入背包的物品序列。

3.2 任务分配问题

问题:把n个任务分配给n个人,每个人完成每项任务的成本不同,并且一个人只能被分配一个任务,任务分配问题要求分配的总成本最小的最优分配方案。

想法:
首先划分问题上下界,我们可以使用贪心法得到一个合理的上界,也就是顺序分配任务,然后从未被分配的人中选择开销最小的。获得合理的下界则只需要将每个任务所需要的最小执行时间加起来即可,但是这通常不是一个可行解,因为这可能会给一个人分配两个任务。那么,假设我们已经给前i个人员分配了任务,并且花费了成本v,那么限界函数=v+剩余人员中每个人员完成一个任务需要的最小时间之和。

接下来是详细过程:任务分配问题的解空间树是一颗满n叉树,其中第i层节点的第j个子节点表示将任务j分配各第i个人员。从根节点出发,没有分配任务,计算根节点的限界函数值后存入PT表,接着遍历根节点的n子节点,第i个子节点表示将第i个任务分配给第1位工作人员。并且检查节点的限界函数,如果限界函数不超出上界则将其加入PT表中。重复上述过程,选择PT表中限界函数值最小的节点出来,并且遍历该节点的子节点,将不超出上界的加入PT表中。当遍历到了叶子结点的时候,则求得了最优解,使用回溯从叶子结点回溯到根节点就可以求出其任务分配序列。

3.3 批处理作业调度问题

给定n个作业集合,每个作业都有三项任务分别在三台机器上完成,每个作业都必须先由第一台机器处理,再交给第二台机器处理,最后由第三台机器处理。则求确定n个作业的最优处理程序,使得完成处理所需要的时间最短。

分析:
批处理调度的最优调度应该使得机器1没有空闲时间,机器2和机器3的空闲时间最小。那么如何在不实际求解问题下得到一个近似解呢?

你可能感兴趣的:(算法之路,算法,数据结构)