上一节我们了解了什么是分支限界法,按照惯例我们要根据例题来总结分支限界法的思想和模式。
简单来说我们学习到分支限界法实际上是对解空间树的广度优先遍历,而其核心可以拆解为分支和限界两个词语,分支代表按照广度展开的可能分支,而限界代表我们所规定的剪枝的上界和下界条件。将可行的结点加入活结点表,不可行的则剪枝,直至我们找到符合输出条件的分支。
让我们回顾一下装载问题,
这是一个子集树问题,还记得我们用回溯法来解决的时候,就是依次遍历全部的解空间并按照限定条件来剪枝。现在我们要用分支限界法来解决,那么对于这个题目来说我们要搞清楚分支,从根节点开始就是c1c2c3,如果选择了c1那么分支就是c2c3,选择c1c2分支就是c3。当然可以不选。限界就是规定总重量不超过c并且要求记录最大的bestw。
(注意MaxLoading不是只执行一次,而是需要遍历整个子集树)
改进了之后增加了一个剪枝条件,对于当前重量Ew+剩余重量r<=bestw的进行剪枝,因为全加上也无法超过bestw,没必要再遍历。
以上代码是队列式的分支限界法,还有一种优先队列式的分支限界法。
找了网上的一张图
简单来说,对于一个货物,我们的选择只有选中或者不选中。想要尽可能装重一点的货物,那么其上界就要尽可能大。在图中所给的例子中我们发现,up=所有选中的货物重量+可供选择的货物重量,它所代表的是最大重量的上界,那么如果我们要寻找最优解,肯定要从上界大的子树里寻找。这个up的值当且仅当我们明确某货物不会被选中,才会减去它的重量,比如第二层发现8+6=14>c1=12。在超重剪枝的情况下我们就会直接走到右子树。而在第三层,虽然左子树上界较大,但是我们发现最终up较大值是在右子树当up=11时,这也是为什么我们不再遍历A到C这条路径,因为A到C这里up也是11,不大于我们记录的bestw=11(bestw仅当为叶子节点才更新),所以剪枝了。
从这两题我们总结一下分支限界法的一般规律:
分支限界法的概念是分支和限界,分支即我们如何选取拓展节点,限界即我们需要限定的上界和下界。判断是否得到了解的条件较多:
比如如果我们的解达到了上界,说明已经是最优了,那么就是我们所求的解。
如果某条分支的上界已经低于总体下界,那么说明已经不在解范围内,我们就需要剪枝。
而优先队列实际上表达的是对界限的动态更新,每层的上界或者下界都是实时更新着的,我们每次所遍历的最优解都可以作为新的上界或下界,这样做的好处是将一部分的路径可以直接剪枝,使得计算量更少。