24 KiB
第八章 分支限界法 (Branch and Bound Method)
目录总览
本章主要包含以下七个部分的内容:
-
8.1 一般方法:介绍分支限界法适用的问题特点、基本思想、抽象化描述、检索方式及FIFO检索。
-
8.2 LC-检索:讲解智能选择结点的LC-检索的优点、成本函数量化方法、定义及成本估计函数。
-
8.3 15-谜问题:通过经典实例分析状态空间树、函数定义、判定定理及不同检索方式的对比。
-
8.4 求最小成本的分支限界法:探讨如何利用成本估计函数与最优解上界
U加速寻找最优解,并给出抽象算法(FIFOBB、LCBB)。 -
8.5 带有期限的作业调度问题:具体实例的解空间构造、约束函数、成本估计及算法运行过程。
-
8.6 货郎担问题(TSP):具体实例的成本下界函数设计及LC-分支限界法的实例运行。
-
8.7 小结:总结分支限界法与回溯法的异同及核心掌握点。
8.1 一般方法
1. 方法适用的问题特点
-
适用范围:与回溯法类似,分支限界法同样适用于求解组合数较大的问题,特别是组合优化问题(即求最优解的问题)。
-
基本概念继承:在分支限界法中,解向量的表达、显式约束条件、隐式约束条件、解空间和解空间树等概念均与回溯法相同。
-
主要区别:两者的主要区别在于 E-结点(即扩展结点)的处理方式不同。
-
学术观点:清华大学出版社出版的屈婉玲等编著的《算法设计与分析》中认为:“分支限界是回溯算法的变种”。
2. 分支限界法的基本思想
-
准备工作:针对问题定义解空间树结构(元组、显式约束、隐式约束),并检验问题是否满足多米诺性质,以寻找一个可行解。
-
搜索规则:假设当前寻找一个答案结点,按下列方式搜索解空间树:
-
如果根结点
T是答案结点,则输出T并结束操作;否则令T成为当前的扩展结点(E-结点)。 -
生成 E-结点的所有儿子结点,并对每个儿子结点
X进行判断: -
如果
X是答案结点,输出到根结点的路径,操作结束; -
如果
X满足约束函数 $B$,则将X添加到活结点表中;否则直接舍弃(剪枝) $X$。 -
从活结点表中选出下一个结点成为新的 E-结点,重复上述操作。如果活结点表为空,则算法以失败结束。
-
约束函数剪枝作用:避免生成那些不包含可行解的子树。
3. 算法8.1 分支限界法的抽象化描述
- 核心伪代码逻辑:
procedure BB(T)
if T是答案结点 then 输出T; return endif
E ← T
将活结点表初始化为空
loop
for E的每个儿子X do
if X是答案结点 then 输出从X到T的那条路径; return; endif
if B(X) then call ADD(X); PARENT(X) ← E endif
repeat
if 表中不再有活结点 then print("no answer node"); return; endif
call LEAST(E)
repeat
end BANDB
- 辅助函数含义:
ADD(X)用于将结点X添加到活结点表中;LEAST(E)用于从活结点表中选中一个结点赋值给 $E$,并从表中删除该结点。 - 思考题:如果想获得所有可行解,算法该怎样设计?
4. 分支限界法的不同检索方式
根据活结点的检索次序,分支限界策略主要分为以下两种:
- 顺序队列式:
- 活结点依赖进入活结点表的先后顺序从表中被选出。
- 最常见的是先进先出方式(FIFO),活结点表采用队列实现。若
LEAST遵循 FIFO,算法即为 FIFO-检索。
- 优先队列式:
- 活结点依赖成本估计函数 $\hat{c}$,
\hat{c}最小或最大的活结点优先从表中被选出。 - 活结点表采用极小堆或极大堆实现。若
LEAST遵循极小堆优先队列,算法即为 LC-检索。
- 活结点依赖成本估计函数 $\hat{c}$,
5. 理解FIFO-检索(以4-皇后问题为例)
- 运行分析:在4-皇后问题中,FIFO-分支限界法顺次处理了31个结点(结点选择盲目,按层序生成,处理顺序为2, 18, 34, 50, 8, 13, 29, 35, 51, 56, 14, 30, 38, 54...),而回溯法(深度优先)一共仅处理了16个结点。这说明纯粹的FIFO检索在某些问题上搜索效率并不高。
8.2 LC-检索(Least Cost Search)
1. LC-检索的优点
- 盲目性问题:在 FIFO-分支限界法中,对下一个 E-结点的选择是死板且盲目的,没有给可能快速检索到答案结点的活结点赋予任何优先权。
- 智能化改进:理想状态下,对活结点表使用一个“有智力的”成本函数来选取下一个 E-结点,给那些可能导致答案结点的活结点赋予优先次序,从而加快到达答案结点的检索速度。
2. 成本函数 c 的量化方法
令 X 是当前结点,c(X) 定义为以 X 为根的子树中的最小成本值。常见的量化方法有三种:
- 方法1:寻找生成数目最少的答案结点(基于生成答案结点之前需要生成的结点数定义)。
- 方法2:寻找路径长度最短的答案结点(基于答案结点的路径长度定义)。
- 方法3:寻找使目标函数取极值的答案节点,即最优解(基于问题描述中的目标函数定义)。
- 注:本章中,当问题不存在目标函数时,默认采用方法2(路径长度)来定义函数。
3. 成本函数定义
- 真实成本:对状态空间树里的解结点
X定义真实成本函数 $\text{cost}(X)$,当X是答案结点时其值为从根到X的真实代价(如路径长度、目标函数值),当X不是答案结点时其值为 $\infty$。 - 上帝视角成本函数 $c(X)$:
c(X) = \begin{cases} \text{cost}(X) & \text{叶节点} X \text{是答案节点} \\ \min\{\text{cost}(P) \mid \text{答案节点} P \in \text{子树} X\} & \text{子树} X \text{中包含答案节点} \\ \infty & \text{子树} X \text{不包含答案节点} \end{cases} - 思考题:在什么样的状态空间树中会出现答案结点
X不是叶结点的情况?(答:$k$-元组表达时)。 - 实例:设
c(X) =到达答案结点的最短路径长度。蓝色结点表示不能到达任何答案结点($c=\infty$),叶结点10(路径长度3)和11(路径长度4)是答案结点,则 $c(10)=3$,$c(8)=3$,$c(3)=3$。基于对活结点表的检索,可快速找到结点10。
4. 成本函数的问题与解决策略
- 面临问题:要精确得到函数
c非常困难。因为c(X)基于答案结点的真实成本定义,为了求出该值,必须先生成整棵状态空间树,其计算工作量与原问题具有相同的复杂度。 - 替代方案:引入一个易于计算的成本估计函数 $\hat{c}(X)$ 来替代
c(X)对活结点表进行检索。定义\hat{c}(X)时需要满足:- 很容易确定根结点到
X已经产生的成本; - 很容易估计从
X到一个答案结点可能会产生的成本。
- 很容易确定根结点到
5. 成本估计函数 \hat{c} 的定义与要求
- 数学公式:
\hat{c}(X) = f(h(X)) + \hat{g}(X)- $h(X)$:根结点到结点
X的实际成本。 - $\hat{g}(X)$:从
X到最小成本答案结点的估计(未来)成本。 - $f$:非负函数,用于调整
h和\hat{g}在成本估计函数中的影响比例。
- $h(X)$:根结点到结点
- 对
\hat{c}(X)的硬性要求:- 易于计算,能够替代对活结点表的检索。
- 必须满足下界性质:$\hat{c}(X) \le c(X)$。
- 当答案节点
X是叶节点时,满足 $\hat{c}(X) = c(X)$。
6. LC-检索与特殊情况
- LC-检索的决策:每次均选取成本估计函数
\hat{c}(X)的值最小的活结点作为下一个 E-结点。 - BFS(广度优先)的本质:当
f(h(X)) = \text{根到结点} X \text{的路径长度}且\hat{g}(X) = 0时,BFS就是LC-检索的一种特殊情况。 - 思考题:只用
\hat{g}(X)为结点排序是否适合(即 $f(h(X))=0$)?- 后果分析:当
\hat{c}(X) = \hat{g}(X)时,假设子树X的儿子结点是 $Y$,很容易存在 $\hat{g}(Y) \le \hat{g}(X)$。若活结点表中其他结点估计值均大于 $\hat{g}(X)$,则X成为 E-结点后,Y紧接着也会成为新的 E-结点。该过程会导致算法一直纵深方向检索,直到子树X全部检索完毕才可能跳出。 - 结论:只考虑未来可能的代价,属于“乐观的冒进”,可能会丢失掉更靠近根的答案结点,导致结果不理想。
- 后果分析:当
- 总结:LC-检索通过
\hat{c}进行优先选择,使得算法倾向于选择更靠近答案结点,同时又离根结点较近的结点。
8.3 15-谜问题
1. 问题描述
- 在一个分成16格的方形棋盘上放有15块编了号码的牌,要求通过一系列合法的移动(将邻接空位置的牌移入空位),将初始排列转换成指定的目标排列。
2. 状态空间树
- 问题状态:每一个棋牌布局都是一个状态。
- 树结构:棋牌每移动一次,就会产生一个新的布局。当前结点
X的儿子结点是X通过一次合法移动到达的布局状态。整棵树由所有可从初始状态经过一系列合法移动到达的状态构成。 - 移动顺序:边表示为空格的一次合法移动,按 上、右、下、左 的顺序进行。
- 注:只有初始状态满足某些条件时,才能达到目标状态。
3. 函数定义与判定定理
- 基础定义:对棋盘方格按目标状态的顺序编上1~16号(空格位是16)。
- $\text{POSITION}(i)$:牌面
i在初始状态时的位置号($1 \le i \le 16$)。 - $\text{LESS}(i)$:牌面上满足
j < i且\text{POSITION}(j) > \text{POSITION}(i)的j的数目(即逆序数)。
- $\text{POSITION}(i)$:牌面
- 初始状态判定定理:在初始状态下,如果空格在阴影位置中(按国际象棋盘交替染色),则令 $X=1$;否则令 $X=0$。当且仅当初始状态的
\sum_{i=1}^{16} \text{LESS}(i) + X是偶数时,目标状态才是可达的。
4. 不同检索方式在15-谜问题中的表现
- FIFO-检索:按层序千篇一律地移动。虽然能找到离根最近的答案结点,但不管开局如何,搜索顺序十分呆板,不关心问题的具体实例。
- 深度优先检索:总是采取由根开始的最左路径。呆板而盲目,在搜索过程中极有可能越走越远,远离目标。
- LC-检索的设计:
c(X)定义:从初始排列到达目标排列时,棋牌的最少移动次数。\hat{c}(X)定义:$\hat{c}(X) = f(X) + \hat{g}(X)$。- $f(X)$:从初始排列到状态
X时,棋牌已经移动的次数。 - $\hat{g}(X)$:不在其目标位置的非空白棋牌数目。
- $f(X)$:从初始排列到状态
- 优势:在这种设计下,LC-检索几乎和使用精确函数
c一样有效,其选择性比很多盲目检索方法强得多。
8.4 求最小成本的分支限界法
1. 算法改进的背景
- 基础BB算法的缺陷:在常规的分支限界法中,算法一旦判断出儿子结点
X是答案结点,就会打印路径并直接结束。 - LC-检索的局限:基于LC-检索的算法不一定能直接找到具有最小成本的答案结点。除非对
\hat{c}追加极其苛刻的要求:对于每一对结点 $X, Y$,当c(X) < c(Y)时必须有 $\hat{c}(X) < \hat{c}(Y)$。由于这很难实现,因此必须改进算法。 - 改进思路:改变判断时机。基于LC-检索从活结点表中选出 E-结点后,再判断 E 是否是答案结点,如果是则结束操作。该思路适用于 $n$-元组表达。
2. 算法8.2 找出最小成本答案结点的LC算法
- 伪代码逻辑:
procedure LC(T, ĉ)
E ← T, 将活结点表初始化为空
loop
if E是答案结点 then 输出从E到T的那条路径; return; endif // 取出后判断
for E的每个儿子X do
if B(X) then call ADD(X); PARENT(X) ← E; endif
repeat
if 表中不再有活结点 then print("no answer node"); return; endif
call LEAST(E) // 选择ĉ最小的
repeat
end LC
- $n$-元组与 $k$-元组的处理区别:
- $n$-元组表达:答案结点一定是叶结点,在叶结点处满足等式 $\hat{c}(\cdot) = c(\cdot) = \text{cost}(\cdot)$。由于活结点表中所有结点
L都有 $\hat{c}(E) \le \hat{c}(L)$,因此\text{cost}(E)一定是最小成本,算法一定能终止于最小成本答案结点。 - $k$-元组表达:答案结点可能不是叶结点,只能满足不等式 $\hat{c}(\cdot) \le c(\cdot) \le \text{cost}(\cdot)$,因此算法不一定能终止于最小成本答案结点。为了解决通用性,需要引入剪枝能力更强的界限算法。
- $n$-元组表达:答案结点一定是叶结点,在叶结点处满足等式 $\hat{c}(\cdot) = c(\cdot) = \text{cost}(\cdot)$。由于活结点表中所有结点
3. 加速寻找最小成本的思想(引入限界 $U$)
- 基本思想:在寻找最优解过程中,如果发现某个结点
X不可能导致比当前已知可行解更好的解,则不必再搜索子树 $X$,直接将其剪枝(最优解剪枝)。 - 具体设计:
- 设置一个全局的最小成本上界 $U$,表示当前最小成本不会大于 $U$。
- 如果某个结点的 $\hat{c}(X) > (\text{或} \ge) U$,则无需检索以
X为根的子树。 - 分支限界法求极小化问题时,问题转化为在解空间树中寻找最小成本答案节点:将目标函数作为成本函数 $c$,约束条件作为约束函数 $B$,设计下界估计函数
\hat{c}(X) \le c(X)和上界U进行搜索。
4. 最小成本上界 U 与成本上界函数 u(X)
- 全局上界
U的特征:- 含义:它是当前算法生成过的所有状态结点对最小成本上界估计的最小值。
- 取值:初值设为 $\infty$(或通过启发式方法得到),随着结点的访问不断被改小。
- 作用:检查结点的死活,通过剪枝加快找到最优解。
- 成本上界函数
u(X)的特征:- 含义:它是从根出发到
X的这条指定路径下的最小成本上界估计值。 - 构成:由“根到
X的真实成本”和“X到最小成本答案结点的成本上界估计”两部分构成。 - 要求:易于计算,且满足 $\hat{c}(X) \le c(X) \le u(X)$,在叶子答案结点处 $c(X) = u(X)$。
- 含义:它是从根出发到
5. 界 U 的改值、剪枝及设计技巧
- U 的改值时机:
- 发现一个答案结点
X且\text{cost}(X) < U时,令 $U \leftarrow \text{cost}(X)$; - 发现一个状态结点
X且u(X) < U时,令 $U \leftarrow u(X)$。
- 发现一个答案结点
- U 的剪枝规则:
- 若
U的值来自真实成本(已找到具体可行解),则\hat{c}(X) \ge U的活结点都可以杀死。 - 若
U的值来自成本上界(仅确定存在该上界的解,尚未实际找到),则\hat{c}(X) > U的活结点可以杀死。
- 若
- 统一剪枝技巧:为了应对
U来源不同导致剪枝策略不同的问题,引入一个足够小的正常数 $\epsilon$。当U从u(X)获取数值时,调高一点:$U \leftarrow u(X) + \epsilon$;从\text{cost}(X)获取时保持不变:$U \leftarrow \text{cost}(X)$。此时统一剪枝策略为:当前结点若满足 $\hat{c}(X) \ge U$,则直接杀死。
6. 核心限界算法描述(算法8.3、8.4、8.5)
- 算法8.3 界函数 UB(X, U, ans):
procedure UB(X, U, ans)
if ĉ(X) > U or (ans有结点 and ĉ(X) == U) then return false endif // 界定杀死
if X是答案节点 and cost(X) < U then U ← cost(X); ans ← X endif // 更改U为真实成本
if u(X) < U then U ← u(X); ans ← 0 endif // 更改U为估计上界
return true
end UB
- 算法8.4 求最小成本的 FIFO-分支限界算法 (FIFOBB):利用队列存储活结点。子结点入队时必须通过
B(X)检验和UB检验;出队时若满足 $\hat{c}(E) < U$(或无答案结点且相等)则允许扩展,否则跳过。 - 算法8.5 求最小成本的 LC-分支限界法 (LCBB):利用极小堆存储活结点。当表空,或者堆顶结点的 $\hat{c} > U$(或有答案结点且相等)时,算法结束,此时的
U即为最小成本,从ans核心回溯输出路径。
7. 极大化问题的转化方法
很多问题需要求目标函数的极大值,可以通过以下两种方式解决:
- 方法1(相反数法):取目标函数的相反数作为成本函数 $c$,将问题转化为极小化问题。
- 方法2(镜像修改法):把目标函数直接作为成本函数 $c$,转化为寻找最大成本答案结点。此时满足 $u(X) \le c(X) \le \hat{c}(X)$,全局界
U作为下界会不断增大,\hat{c}(X) < U的结点被杀死。
8. 总结最优解分支限界法
- 剪枝依据:约束函数 $B$(限定是否存在可行解);成本估计函数
\hat{c}(X)和界 $U$(界定是否存在最优解)。 - 剪枝发生点:
X入活结点表时(接受B和U检验);X出活结点表时(接受U检验)。 - 终止条件:活结点表为空;或者活结点表中再没有能通过
U检验的结点。 - 思考题:用回溯法解决最优解问题时,
\hat{c}(X)和界U能否用于提高算法效率?(答:能,即深度优先的分支限界法)。
8.5 带有期限的作业调度问题
1. 问题描述与实例
- 问题定义:
n个作业和一台处理机,每个作业i表示为三元组 $(p_i, d_i, t_i)$(分别代表罚款、期限、处理时间)。若在期限d_i前未完成,则需交付p_i的罚款。目标是选择一个子集J使得选中的作业能在期限内完成,且未选中的作业罚款总数最小(极小化问题)。 - 实例参数:$n=4$,作业分别为:$(5,1,1)$、$(10,3,2)$、$(6,2,1)$、$(3,1,1)$。
- 解空间表达:采用不定长 $k$-元组 $(X_1, \dots, X_k), k \le n$。显式约束:选中的作业下标严格递增 $X_i < X_{i+1}$。隐式约束:作业能在期限前完成。整个解空间树包含
2^n=16个结点。
2. 约束与限界函数设计
- 约束函数 B:通过检验作业完成的可行性,实例中最终有10个活结点通过 B 检验,最优解为 ${2, 3}$,根结点成本 $c(1)=8$。
- 成本估计函数
\hat{c}(X)设计:- 设
S_X是根结点到结点X时选中的作业集合,令 $m = \max{i \mid i \in S_X}$。 - 若
X是可行解,则 $\hat{c}(X) = \sum p_i \quad (i < m, \text{且} i \notin S_X)$;若X不可行,则 $\hat{c}(X) = \infty$。
- 设
- 成本上界函数
u(X)设计:- $u(X) = \sum p_i \quad (i \notin S_X)$,全局上界 $U = \min{u(X)}$。
- 实例中
U的改值轨迹为 $24 \rightarrow 19 \rightarrow 14 \rightarrow 9 \rightarrow 8$。在 FIFO 检索下考虑U的剪枝作用,最终只有 5 个活结点通过了U检验,其余结点均被 kill。
- 运行结果:算法结束时队列为空,最终全局最小成本 $U=8$,
ans对应的最优解结点编号为 9。
8.6 货郎担问题(TSP)
1. 问题描述与实例
- 问题定义:售货员要周游
n个城市,已知各城市之间的有向边成本 $c_{ij} > 0$,求一条每个城市只经过一次并回到起点的最小成本周游路线。 - 复杂度:动态规划求解的时间复杂度是 $O(n^2 2^n)$。分支限界法最坏情况也是 $O(n^2 2^n)$,但对许多具体实例,能花费较少的时间。
- 问题实例:$n=4$,从城市1出发,经过
\{2,3,4\}的排列后再回到1。 - 解空间表达:固定长 3-元组 $(X_1, X_2, X_3)$。显式约束:
X_i \in \{2,3,4\}且互不相同。隐式约束:相邻两点之间必须有边存在。状态空间树共有3! = 6个叶结点。
2. 成本函数与下界函数设计
- 成本函数 $c(X)$:若
X是叶结点,为该周游路线的真实总成本;若X是非叶结点,为其子树中最小成本叶结点的成本。例如,路径 1-2-4-3-1(对应结点12)的成本为 $c_{12}+c_{24}+c_{43}+c_{31} = 10+10+9+6 = 35$。 - 成本下界函数
\hat{c}(X)设计:- 公式:$\hat{c}(X) = f(X) + \hat{g}(X)$。
- $f(X)$:已选定的路线(如 $1, X_1, \dots, X_k$)的实际成本和。
- $\hat{g}(X)$:经过剩余结点回到1的最短距离估计。
- 计算方法:设
S = V - \{1, X_1, \dots, X_k\}为剩余结点集合,l_d表示从城市d出发的最小边成本(不关心具体到达哪个城市)。则当k < n-1时,$\hat{g}(X) = l_{X_k} + \sum_{d \in S} l_d$。 - 根结点(结点1)的下界计算实例:$f(\text{空})=0$,$S={2,3,4}$,从各点出发的最小边之和为 $10+19=29$,故 $\hat{c}(1)=29$。
- 成本上界 U:初始值可通过贪心法获得(实例从1出发通过贪心求得初始 $U=39$)。本例中未额外设计
u(X)函数。
3. LC-分支限界法实例运行过程
- 算法维护一个优先队列(min-堆),初始根结点下界为29。
- 依次扩展
\hat{c}最小的结点:扩展1产生2($\hat{c}=29$)、3($\hat{c}=34$)、4($\hat{c}=39$,等于U直接舍弃)。 - 接着扩展2,产生5($\hat{c}=33$)、6($\hat{c}=34$)。
- 持续选择堆顶元素,当遇到叶子结点12时,发现其路线成本为35,优于当前 $U=39$,故将
U更新为35,ans记录为12。 - 最终,堆顶结点的
\hat{c}值(如结点8的 $\hat{c}=35$)等于全局上界 $U$,满足退出条件,算法成功结束,最优总成本为35,路径由ans=12导出。
8.7 本章小结
1. 分支限界法与回溯法的异同点
- 相同点:
- 同样适用于求解组合数较大的问题或多阶段决策问题。
- 都是在解空间树上搜索答案结点。
- 都会借助约束函数
B进行可行性剪枝。
- 不同点:
- 最本质的区别:E-结点的处理方式不同(回溯法是深度优先单道深入;分支限界法是一次性产生所有儿子,利用队列或堆进行跳跃式扩展)。
- 效率差异:分支限界法可以基于成本估计函数
\hat{c}智能选择下一个结点,在求解最优解问题时效率显著更高。 - 存储空间:分支限界法需要额外维护一个规模可能很大的活结点表(队列或堆),而回溯法不需要,因此分支限界法通常更消耗内存。
2. 分支限界法求最优解的一般流程
- 极小化问题:目标函数作为成本函数
c \rightarrow约束条件作为约束函数B \rightarrow设计下界估计函数\hat{c}(X) \le c(X) \rightarrow设计成本上界U \rightarrow结合进行限界搜索。 - 极大化问题:将目标函数取相反数转化为极小化问题;或者做镜像修改(目标函数作为
c寻找最大成本,满足 $u \le c \le \hat{c}$,U作为下界不断增大并杀死更小估计值的结点)。 - 剪枝的两大发生点:一是
X进入活结点表时(接受B和U检验),二是X离开活结点表准备作为E-结点时(接受最新更新的U检验)。
3. 课程大纲要求的核心掌握点
- 掌握分支限界法的设计思想、问题特点及不同检索方式的差异。
- 掌握结点成本函数 $c$、下界估计函数
\hat{c}的定义,并能以15-谜问题、作业调度、TSP问题为例,熟练地构造解空间、设计约束函数 $B$、计算限界值,独立设计出高效的分支限界算法并分析其复杂度。