⚠ 当前无法加载公式渲染库(KaTeX 走 CDN),公式可能显示为原始代码——联网后刷新即可。
算法设计与分析 · 课程笔记 · 模块 3(CH05–CH06)

模块 3 · 回溯法 与 分支限界法

合并课件 CH05-回溯v4(129 页)+ CH06-分支v7(98 页) 附:NP 完全性入门(CH05 §5.2)· 解空间树填空是必考题型 整理日期:2026-09-25
本科遗忘急救站 · 搜索树、栈与优先队列(最小堆)

0 · 子集树 vs 排列树 & DFS 回溯 vs BFS/优先队列分支限界

  • 两种解空间树的规模直觉: ① 子集树(0-1 选择,如 0-1 背包、装载、最大团):共 \(n\) 层,每个元素选或不选(二叉树),叶子数 \(2^n\),时间复杂度上界 \(O(2^n)\) 或 \(O(n2^n)\);
    ② 排列树(全排列顺序,如 TSP 旅行商、批处理作业调度):第 \(k\) 层从剩余 \(n-k+1\) 个元素中选一个,叶子数 \(n!\),时间复杂度上界 \(O(n!)\)。
  • 剪枝函数的双刃剑:约束函数(Constraint)剪掉违反题目硬约束的左分支(如超重 \(\text{cw}+w_i > c\));限界函数(Bound)用贪心松弛估算子树能达到的理论最优上界 \(\text{best}\),若连理论上限都比不过当前已找到的最优解 \(\text{bestp}\),直接剪掉右分支!

自学导航 · 回溯与分支限界:真正理解剪枝

① 前置知识与记号

前置复习:递归调用栈、解空间树、组合与排列。约束剪枝拒绝不可行解;限界剪枝拒绝不可能改善当前最优值的分支。每次剪枝必须能解释其安全性。

② 完整例题

四皇后从第 0 行开始,每行放一个;记录已使用列、主对角线 r−c、副对角线 r+c。合法列序列 [1,3,0,2] 可作为手算答案。写清递归入口、冲突检测、撤销选择三步。

💡 破题关键与第一步提示(遮答案自测用 · ③ 考前自测(展开题目))

破题切入点:分支限界在最大化问题中为什么需要乐观上界?(👉 先合上下方完整推导,自己动手算完关键步再核对踩分点!)

📝 完整规范推导与评分踩分点(③ 考前自测(展开题目))

分支限界在最大化问题中为什么需要乐观上界?何时可以安全剪掉分支?

本栏是补充学习材料,考试范围以本学期教师正式通知为准。

考点精练 · 教学型推导与标准答题

考试演算:子集和的搜索树与剪枝

题目:正整数数组 \([2,3,5,7]\),找所有和为 10 的子集。

  1. 状态:当前位置 \(i\)、已选和 \(s\)、当前选集。每层两个分支:取/不取 \(a_i\)。
  2. 约束剪枝:当 \(s>10\) 时,因为剩余全是正数,不可能回落到 10;若 \(s+\) 全部剩余元素之和 \(<10\),也不可能凑够 10。
  3. 深度搜索并在 \(s=10\) 时记录解,得到 \([2,3,5]\) 和 \([3,7]\)。
  4. 最坏需要检查 \(2^n\) 个取舍向量,空间深度 \(O(n)\)(不含输出全部解所需空间)。剪枝改善实例耗时,但通常不改变指数级最坏上界。
💡 破题关键与第一步提示(遮答案自测用 · 自己做:为何负数出现时不能使用「当前和超目标」剪枝?)

破题切入点:因为后续负数可能将和减小,例如目标 10、当前和 12、剩余元素 −2,仍能得到解。(👉 先合上下方完整推导,自己动手算完关键步再核对踩分点!)

📝 完整规范推导与评分踩分点(自己做:为何负数出现时不能使用「当前和超目标」剪枝?)

因为后续负数可能将和减小,例如目标 10、当前和 12、剩余元素 −2,仍能得到解。剪枝必须依据题目约束证明,不可机械套用模板。

与分支限界区别:最大化问题的“乐观上界”若不超过已知可行解值,则该分支可以剪掉;保证正确性的逻辑与仅判断可行性不同。

修订版 · 重点核对

先看:本模块易错点与补充

纠错与边界
  • 回溯既可找所有可行解,也可找到一个解或最优解,不应把“寻找所有解”当作必要定义。
  • “第一艘船尽量装满”只给出第一艘可行的最大装载量;第二艘能否装完剩余箱,还需总重量不超过两船容量和及二船装载检验。
  • Python n 皇后搜索中用列与两条对角线去重,每层回溯都要恢复状态。

0 · 回溯思想与三结点CH05 S4–11, 36–48

大白话 · 回溯 = 走迷宫 把问题的所有可能解组织成一棵解空间树(根=空解,叶=完整解),然后深度优先探索:能走就走,走不通(不满足约束 / 不可能更优)就退回上一步换条路。相比枚举全部路径,剪枝砍掉大量子树。被称为“通用解题法”——没有套路可用时的兜底方案。
核心概念(填空题)
  • 扩展结点:正在产生儿子的结点;活结点:自身已生成但儿子未全部生成;死结点:儿子已全部生成。
  • 显式约束:对分量取值范围的限定;隐式约束:为构成解而对不同分量间施加的约束(如皇后不同列、不同斜线)。
  • 剪枝函数:约束函数剪去不可行子树 + 限界函数剪去得不到最优解的子树。回溯=DFS+剪枝;分支限界=BFS+剪枝(判断题!)。
  • 空间复杂度:回溯只存根到当前结点的路径,\(O(h(n))\)(h 为树高)——显式存整个解空间要 \(O(2^{h(n)})\)。
本模块考试重点(算法填空的固定出题区)
  1. 算法填空——Review 原题风格:回溯递归框架挖空(边界判断 / 扩展 / 剪枝 / 递归调用 / 撤销),框架要默到肌肉记忆;
  2. 解空间树计数——子集树共 2ⁿ 个结点(n 件物品)、排列树 n! 个叶子(填空秒答);
  3. 回溯 vs 分支限界三区别——简答必背(求解目标 / 搜索方式 / 节点选择策略);
  4. 算法设计——TSP / 装载 / n 皇后 / 0-1 背包回溯版:写清解空间类型、剪枝函数(约束 + 限界)、搜索过程;
  5. 本章末尾的 P/NP/NPC 入门是模块 4 的台阶,别跳。
答题规范(本章特别版) ①填空按框架的标准变量名(x[k]、cw、bestw 之类按题面给的名字);②算法设计题画一棵局部解空间树辅助说明(不写程序,文字 + 树图);③分支限界题要写明用队列式(FIFO)还是优先队列式,并给出前几步的扩展顺序。
数学手生?增长率比较(对数<幂<指数)、求和公式、矩阵运算的"三分钟复习"在上级目录 《数学基础工具箱》第 3、4、5 节;考前看第 8 节"急救包"。

1 · 通用框架与两类解空间树 ★★(算法填空必考)CH05 S11–19; Review S110–111

递归回溯通用框架(会默写)
void backtrack(int t) {          // 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))   // 剪枝:约束 && 限界
                backtrack(t + 1);
        }
}
迭代形式:while(t>0) 展开/回退(考试少考,了解)。
两类解空间树 ★★
子集树排列树
适用从 n 元集选子集(每物选/不选)求 n 元的排列
叶结点 / 遍历时间\(2^n\) 个叶 / O(2ⁿ)\(n!\) 个叶 / O(n!)
典型问题0-1 背包、装载、最大团TSP、批处理作业调度、n 皇后
排列树框架(填空题原题:①= t,②= n,③= swap(x[t], x[i]),回溯时再 swap 一次):
void backtrack(int t) {
    if (t > n) output(x);
    else
        for (int i = t; i <= n; i++) {   // ①②
            swap(x[t], x[i]);            // ③
            if (constraint(t) && bound(t)) backtrack(t + 1);
            swap(x[t], x[i]);            // 恢复现场
        }
}
① 子集树 Subset Tree(2ⁿ 叶结点 · O(2ⁿ)) x₁=1(选) x₁=0(不选) x₂=1 x₂=0 x₂=1 x₂=0 代表问题:0-1背包、装载问题、最大团、子集和 框架:for i in {1, 0}: x[t]=i; if OK(t): Backtrack(t+1) ② 排列树 Permutation Tree(n! 叶结点 · O(n!)) swap(1,1) swap(1,2) swap(1,3) 代表问题:旅行售货员 TSP、批处理作业调度 ⚠ 填空必考:for i=t..n: swap(x[t],x[i]); Backtrack(t+1); swap(x[t],x[i])
图:回溯法两类标准解空间树(左:0/1 二叉子集树;右:度数逐层递减 n → n-1 → … → 1 的排列树)

2 · TSP / 0-1背包 / 装载(回溯版)

2.1 旅行商问题 TSP(排列树)CH05 S55–65

周游回路 = 固定起点 1,对 \(x[2..n]\) 全排列,末尾加回 \(x[1]\)。剪枝:当前部分和 \(cc\) ≥ 已知最优 bestf 即剪;再加上“图中有边”的可行性检查。n=4 时解空间 4!=24 个叶。

2.2 0-1 背包(子集树 + 双剪枝)★CH05 S66–70; Review S116–118

剪枝设计(大题模板) 约束函数(左子树,装入):\(cw+w_i\le c\) 才能进左子树。
限界函数(右子树,不装):计算经过当前结点的价值上界 = 当前价值 cv + 剩余物品按单位价值贪心装满剩余容量的价值(可拆!);上界 ≤ bestv 时剪去右子树。
例(课件原例)· n=4, c=7, p={9,10,7,4}, w={3,5,2,1}
单位价值 {3,2,3.5,4}。装物品 4,3,1 后剩余容量 1,装 2 的一部分 → 上界的“贪心部分”。计算上界时剩余容量×单位价值即可(可拆思想)。最优解 x=(1,0,1,1):w=6≤7,v=20。
另一例(Review S118,n=3, w={20,15,10}, v={20,30,25}, C=25):画解空间树并标搜索过程——最优 (0,1,1),w=25,v=55。

2.3 装载问题(两艘船)CH05 S71–77

n 个集装箱装两艘载重 \(c_1,c_2\) 的船。有解时最优策略:① 第一艘尽量装满(等价于特殊的 0-1 背包:子集和最接近 \(c_1\))→ 回溯子集树;② 剩余装第二艘。剪枝:约束 \(cw+w_i\le c_1\);限界 \(cw+r>wm\) 才展开右子树(r=剩余箱总重)。例:n=4, c₁=12, w={8,6,2,3} → 第一船装 {8,2}?不,可装 {8,3}=11 或 {6,2,3}=11 或 {8,2}=10… 目标是尽量靠近 12 而非一定装满 12:{6,2,3}+8=19>12;{8,3}=11、{6,2,3}=11 → 装满 12 需 {8,2}=10 +3=13 超;实际第一船最优 wm=11({8,3} 或 {6,2,3})。能否将剩余箱全装到第二船,仍须检查第二船载重 c₂:总重量为 19,故此例要求 c₂≥8。

3 · n 皇后 / 最大团 / 批处理 / m 着色

3.1 n 皇后(排列树 + 隐约束)★CH05 S78–87

建模与剪枝 解向量 \(x[1..n]\),x[i]=皇后 i 的列号(第 i 行放第 x[i] 列)。显约束 \(x_i\in\{1..n\}\);隐约束:① \(x_i\ne x_j\)(不同列)② \(|i-j|\ne|x_i-x_j|\)(不同主/反对角线)。剪枝函数:
bool place(int k) { for (int i = 1; i < k; i++)
    if (x[i]==x[k] || abs(k-i)==abs(x[i]-x[k])) return false;
    return true; }
4 皇后:解 (2,4,1,3) 与 (3,1,4,2)。解空间是完全 n 叉树(Review 标注为“排列树”视角)。

3.2 最大团 / 最大独立集CH05 S88–98

团 = 两两有边的完全子图(极大、最大);独立集 = 两两无边。G 的最大团 = 补图 G′ 的最大独立集(等价,判断题)。回溯:子集树;约束=新顶点与团内每个顶点都有边;限界=cn+(n−i)≤bestn 剪右子树。O(n2ⁿ)。

3.3 批处理作业调度(排列树)CH05 S99–104

n 个作业各两道工序,先机器 1 后机器 2,求调度使完成时间和最小。例 n=3:6 种调度完成时间和 19,18,20,21,19,19 → 最优 (1,3,2)=18。排列树 + 剪枝:当前完成时间和 ≥ 最优值即剪。机器 2 有空闲与积压两种情况要分别累计。

3.4 图的 m 着色CH05 S105–126

给定无向图 G 与 m 色,相邻顶点异色。解空间:高 n 的完全 m 叉树。剪枝:与已着色邻居不同色(Bound 检查)。应用:考试排期(课程=顶点、学生重叠=边、颜色=时段);地图着色经对偶图转化为顶点着色(四色定理:平面图 4 色足够,1976 年机器证明)。问“存在性”(能否 m 着色)与“最少色数”两种问法。

3.5 回溯效率分析CH05 S127–129

效率取决于:解空间结构(重排原理:取值少的分量优先)、产生 x[k] 的时间、满足剪枝的结点数、约束/限界函数本身的计算代价——剪枝函数不宜太贵。

📄 期末禁止写代码:n 皇后问题(回溯法深度优先搜索) · 自然语言标准作答四步模板
  1. ① 状态/子问题定义与符号声明:解空间表示为 \(n\) 元向量 \(x[1..n]\),其中 \(x[t]\in\{1,\dots,n\}\) 表示第 \(t\) 行皇后放置的列号。搜索树为高度 \(n\) 的完全 \(n\) 叉树(或全排列树)。
  2. ② 核心递推方程 / 贪心策略 / 搜索剪枝准则:约束剪枝函数 \(Place(t)\):第 \(t\) 行皇后与前面任意第 \(i\) 行(\(1\le i < t\))皇后不同列且不同正反斜线,即 \(x[i]\ne x[t]\) 且 \(|x[i]-x[t]| \ne |i-t|\)(编程时可用列集 `cols`、主对角集 `r-c`、副对角集 `r+c` 实现 \(O(1)\) 判重)。
  3. ③ 算法自然语言分步流程(严禁贴 C/Python 语法):第一步:从第 \(t=1\) 行开始递归搜索;第二步:若 \(t>n\) 说明找到一组完整合法布局,记录解并返回;第三步:否则在当前第 \(t\) 行依次尝试列号 \(col=1\dots n\),调用约束函数检验冲突;第四步:若不冲突则标记占用并递归进入第 \(t+1\) 行,回溯返回时务必撤销当前行的列与对角线占用标记。
  4. ④ 时间与空间复杂度严格推导:解空间树结点总数上界 \(O(n^n)\)(排列树视角为 \(O(n!)\)),每次约束检查 \(O(1)\)(哈希集)或 \(O(n)\),递归栈与状态标记空间复杂度 \(O(n)\)。
🐍 Python 求职机试标准实现(源自 practice_algorithms.html · 在线阅读器)
def n_queens(n):
    """每种方案为逐行皇后列号,最坏指数搜索。"""
    if n < 0:
        raise ValueError('n 不得为负')
    ans, path = [], []
    cols, d1, d2 = set(), set(), set()

    def search(row):
        if row == n:
            ans.append(path[:])
            return
        for col in range(n):
            a, b = row - col, row + col
            if col in cols or a in d1 or b in d2:
                continue
            cols.add(col)
            d1.add(a)
            d2.add(b)
            path.append(col)
            search(row + 1)
            path.pop()
            d2.remove(b)
            d1.remove(a)
            cols.remove(col)

    search(0)
    return ans

4 · NP 完全性入门 ★CH05 S21–33; 什么是P/NP/NPC.ppt

(本节是模块 4 的预告与浓缩;完整展开——含归约链、证明模板、网络流、近似算法——见模块 4。)

两类问题 优化问题(实例集 D、可行解集 S(I)、目标函数 c,求极值);判定问题(答案只有是/否,即映射 \(I\to\{0,1\}\))。NP 完全性理论只针对判定问题(优化问题可转判定:加阈值 k)。
P / NP / NPC / NPH P:多项式时间内可求解的判定问题。NP:多项式时间内可验证一个解的问题(P⊆NP;NP≠“非P”!)。NPC:①属于 NP;②NP 中任何问题都可多项式时间归约到它(两条同时满足)。NPH:只满足条件②——范围比 NPC 广,可以不是 NP。
规约(归约)A ≤p B 把 A 的任意实例多项式时间变换成 B 的实例且答案保持一致 ⟹ B 至少和 A 一样难(“A 可约化到 B” = “会用 B 解 A”)。归约可传递:A≤pB, B≤pC ⟹ A≤pC。方向极易考反(见模块 4 判断题清单)。
NPC 的证明与意义 证明问题 X∈NPC:①证 X∈NP(给出多项式验证算法);②选一个已知 NPC 问题 A,证 A ≤p X(构造映射 + 证 iff 正确性)。第一个 NPC 问题:逻辑电路可满足性(Circuit-SAT),Cook(1971)证明;此后 SAT、Hamilton 回路、TSP(判定版)、背包等相继入列。意义:任一 NPC 问题找到多项式算法 ⟹ P=NP。学界共识 P≠NP。

经典 NPC 问题清单(判断题常客):SAT / 3-SAT、0-1 背包(判定版)/ 子集和、TSP、Hamilton 回路、顶点覆盖、团、独立集、图的 m 着色(m≥3)。

🚨 期末大题铁律:要证新问题 B ∈ NPC,归约箭头必须从【已知 NPC 问题 A ≤ₚ 待证问题 B】(方向反了直接零分!) SAT Cook定理源头 ≤ₚ 3-SAT 每子句3文字 ≤ₚ 最大团 Clique G有大小k的团 取补图Ḡ 顶点覆盖 VC Ḡ有|V|-k覆盖 ≤ₚ 子集和 Subset Sum ≤ₚ 0-1背包 判定版 哈密顿回路 HC 经过每顶点恰好1次 TSP 判定 边权0/1转化 ★ 三大等价桥:G 有 k-团 ⟺ Ḡ 有 k-独立集 ⟺ Ḡ 有 (|V|-k)-顶点覆盖
图:算法课大纲核心 NP 完全问题多项式归约树(SAT → 3-SAT → 团 → 独立集/顶点覆盖 → 子集和/背包 & HC → TSP)

5 · 分支限界:思想与回溯的三大区别 ★★CH06 S3–24; Review S80–82

大白话 回溯像走迷宫(一条道走到黑,不行退回来);分支限界像水波扩散(涟漪一圈圈向外,找最近的出口)。都是解空间树上搜索 + 剪枝,但方向和目标不同。
回溯 vs 分支限界(三区别,简答必背)
回溯法分支限界法
求解目标找出满足约束的所有解找出一个解或某种意义下的最优解
搜索方式深度优先 DFS广度优先 BFS / 最小耗费(最大效益)优先
活结点机会可多次成为扩展结点只有一次机会成为扩展结点(一次性产生全部儿子)
补充:分支限界存储活结点表,空间开销远大于回溯的 O(h(n))——内存受限时回溯更可行。
求解步骤(六步) ① 定义解空间(编码)→ ② 确定解空间树结构 → ③ 确定界 [down, up](down 常用贪心可行解,up 常用松弛/贪心上界)→ ④ 扩展结点一次性产生全部儿子,估算目标函数值,低于下界的丢弃 → ⑤ 剩余儿子入活结点表 PT → ⑥ 按分支策略从 PT 取下一结点扩展,直到 PT 空或找到叶结点最优解。要重构最优解需在结点中保存根到该结点的路径。

6 · 队列式 / 优先队列式

两种分支限界法 队列式(FIFO):活结点表=普通队列,先进先出逐个扩展——就是朴素 BFS。
优先队列式:每个活结点带优先级(耗费最小/效益最大),用堆选取——跳向最有希望的结点,通常更快到达最优;叶结点成为扩展结点时即可停(其界已压过所有活结点)。FIFO 与优先队列的 PT 表数据结构不同(队列 vs 堆)——思考题原话。

7 · 六大经典问题(分支限界版)

问题解空间界 / 优先级设计要点
0-1 背包子集树上界 ub=贪心(单位价值装满剩余容量);例:W=10,v₁/w₁=10 → 根 ub=100,贪心可行解给 down=40左儿子=装入(须 ≤c);每结点存路径以重构解
单源最短路径树(路径前缀)优先队列取当前 length 最小者扩展;dist[j] 作控制约束(新长度 < dist[j] 才入队)非负权;先到 t 的叶即最短(BFS 性质保证)
装载子集树优先级 = 当前载重 cw+剩余 r;约束 cw+w≤c₁叶结点成为扩展结点即可断言最优;等价于子集和最接近 c₁
布线问题网格 BFS队列式:从起点向上下左右扩散,先到达目标 b 的即最短(否则它会更早入队);记录前驱回溯构造路径回溯不适用:固定方向 DFS 会沿死路越走越远(思考题原话)
最大团子集树优先级 un=cn+r(当前团顶点数+剩余可选);约束:与团内每点有边cn=当前团顶点数;叶结点 un=cn 时停
TSP(售货员)排列树最小堆;优先级 lcost(当前费用下界)s=n−1 层叶结点若可行且更小则更新;叶成为扩展结点时其余活结点界均不更小,算法结束

另有:批处理作业调度(3 机器版:下界 sum3db=机器 1、2 无空闲且最后是机 3 时间最短作业时的理想值;例 4 作业下界 36);电路板排列(排列树,最小化连接块密度,优先队列式)。

📄 期末禁止写代码:0-1 背包问题(优先队列式分支限界法) · 自然语言标准作答四步模板
  1. ① 状态/子问题定义与符号声明:首先将物品按单位重量价值 \(v_i/w_i\) 降序重排。解空间为高度 \(n\) 的子集树,活结点记录当前层号 \(i\)、已装重量 \(cw\)、已获价值 \(cv\) 及线性松弛上界 \(ub\),维护全局当前最优值 \(bestv\)。
  2. ② 核心递推方程 / 贪心策略 / 搜索剪枝准则:可行性剪枝(左孩子装入物品 \(i\)):仅当 \(cw + w_i \le C\) 时生成左孩子并尝试更新 \(bestv\);上界限界函数 \(Bound(i,cw,cv)\):对剩余容量 \(C-cw\) 贪心装入后续整件物品,放不下时用下一件物品的单位价值装满剩余空隙得分数背包上界 \(ub\);仅当 \(ub > bestv\) 时才将孩子结点压入最大优先队列。
  3. ③ 算法自然语言分步流程(严禁贴 C/Python 语法):第一步:按 \(v_i/w_i\) 降序排列物品,计算根结点上界并压入以 \(ub\) 为优先级的大根堆;第二步:每次弹出堆顶 \(ub\) 最大的活结点作为扩展结点,若其 \(ub\le bestv\)(由于堆单调性)算法可直接终止;第三步:分别考察左分支(选第 \(i\) 件,需过容量约束与上界检验)和右分支(不选第 \(i\) 件,需过上界检验),将合格孩子入堆;第四步:堆空或提前剪枝终止时返回 \(bestv\)。
  4. ④ 时间与空间复杂度严格推导:最坏情况子集树有 \(O(2^n)\) 个结点,单次计算上界耗时 \(O(n)\),堆操作 \(O(n)\),最坏时间 \(O(n 2^n)\),活结点优先队列空间最坏 \(O(2^n)\),但平均剪枝效率远优于回溯。
🐍 Python 求职机试标准实现(源自 practice_algorithms.html · 在线阅读器)
def knapsack_branch_and_bound(weights, values, capacity):
    """优先队列式分支限界求解 0-1 背包最优值(按单位价值线性松弛上界剪枝)。"""
    items = sorted(zip(weights, values), key=lambda x: x[1] / x[0], reverse=True)
    n = len(items)

    def bound(idx, cur_w, cur_v):
        rem = capacity - cur_w
        b = float(cur_v)
        while idx < n and items[idx][0] <= rem:
            rem -= items[idx][0]
            b += items[idx][1]
            idx += 1
        if idx < n and rem > 0:
            b += rem * (items[idx][1] / items[idx][0])
        return b

    best = 0
    pq = [(-bound(0, 0, 0), 0, 0, 0)]  # (-ub, idx, cur_w, cur_v)
    while pq:
        neg_ub, idx, cur_w, cur_v = heappop(pq)
        if -neg_ub <= best or idx == n:
            continue
        w, v = items[idx]
        if cur_w + w <= capacity:
            nv = cur_v + v
            if nv > best:
                best = nv
            ub_left = bound(idx + 1, cur_w + w, nv)
            if ub_left > best:
                heappush(pq, (-ub_left, idx + 1, cur_w + w, nv))
        ub_right = bound(idx + 1, cur_w, cur_v)
        if ub_right > best:
            heappush(pq, (-ub_right, idx + 1, cur_w, cur_v))
    return best

8 · 公式速查(一页纸素材)

回溯框架DFS + constraint(约束) + bound(限界)=剪枝函数;空间 O(h(n))
两类树子集树 2ⁿ 叶 / O(2ⁿ)(背包、装载、最大团);排列树 n! 叶 / O(n!)(TSP、批处理、n 皇后)
排列树要点swap(x[t],x[i]) → 递归 → swap 回
回溯 vs 分支限界所有解 vs 一个/最优解;DFS vs BFS/优先级;多次扩展 vs 一次扩展;省空间 vs 费空间
分支限界两种队列式 FIFO;优先队列式(最大堆=效益,最小堆=耗费)
0-1 背包限界约束 cw+w≤c;限界 = cv + 剩余容量按单位价值贪心装满的可拆价值
装载限界右子树剪枝:cw+r > bestw 才展开
n 皇后隐约束xᵢ≠xⱼ 且 |i−j|≠|xᵢ−xⱼ|
最大团G 最大团 = 补图最大独立集;O(n2ⁿ)
布线BFS 先到即最短;前驱数组回溯路径

9 · 自测(含算法填空真题)

算 法 填 空(Review 原题)
子集树框架:if (t>n) _①_(output(x))else for (int i=0; _②_; i++)(i<=1){ _③_; if (constraint(t)&&bound(t)) backtrack(t+1); }(x[t]=i)。
排列树框架:for (int i=__①__; ②; i++) { ③; if(…) backtrack(t+1); ④; }。(t;i<=n;swap(x[t],x[i]);swap 回)
判 断 / 选 择(历年风格)
  1. 一个活结点最多有一次机会成为扩展结点的是:A 回溯法 B 分支限界法。(B——Review 选择原题)
  2. 回溯法只能寻找所有解。(×;也可找到第一个可行解或最优解,取决于目标与剪枝方式。)
  3. 分支限界法的存储空间比回溯法小。(×,相反)
  4. 最大团问题与最大独立集问题等价。(√——经由补图)
  5. 布线问题用回溯法同样高效。(×,固定方向 DFS 会沿死路走远,应 BFS)
算 法 设 计(Review 原题)
n=3, C=30, w={16,15,15}, v={45,25,25} 的 0-1 背包:
① 画解空间树(子集树 8 叶);② 写约束(cw+wᵢ≤30)与限界(设 r=剩余价值,r+cv≤bestv 剪右子树);③ 给出用分支限界求解的过程(贪心可行解 (1,0,0) 价值 45 作下界;上界=按单位价值装满)。参照 §7 表格模板作答。

🎯 考场题型信号词 → 破题套路速查表 期末冲刺必背 · 信号词秒配定理与防扣分清单

考场上读题 10 秒内锁定“题干信号词”,直接调用中间列的定理模板作答,并在交卷前对照右列逐条排查高频扣分点。

🔍 题干信号词 / 设问特征 ⚡ 必用定理 / 核心递推式 / 标准破题套路 🚨 老师批改高频扣分点
简述回溯法与分支限界法的三大核心区别(高频简答/辨析题) 三维度对比:① 搜索目标:回溯求全部可行解或最优解,分支限界专求最优解(或单个可行解);② 搜索方式:回溯是深度优先(DFS),分支限界是广度优先或最小耗费/最大效益优先(BFS/最佳优先);③ 结点扩展:回溯每次仅生成 1 个儿子纵深推进,分支限界一次性生成扩展结点的所有可行儿子 ⚠ 避坑:漏答“扩展结点生成儿子方式不同”这一教材核心踩分点
判断问题解空间树类型(子集树 vs 排列树)并写出递归回溯框架 / 算法填空 从 \(n\) 个元素选子集(0-1 背包/装载/最大团)用子集树(\(0/1\) 二分分支,叶数 \(2^n\),遍历 \(O(2^n)\));求元素全排列(TSP/批处理作业调度)用排列树(`swap(x[t], x[i])` 交换再还原,叶数 \(n!\)) ⚠ 避坑:排列树回溯算法填空中,递归调用 `Backtrack(t+1)` 返回后漏写第二个 `swap(x[t], x[i])` 恢复现场!
设计回溯剪枝函数(约束函数 `Constraint` vs 限界函数 `Bound`) 左分支(选入/装入)重点检查显式可行性约束(如容量 \(cw+w_i\le C\)、与已选团全相连);右分支(不选/放弃)重点检查上界限界函数(如当前价值 + 剩余最大可能价值 \(> bestv\)) ⚠ 避坑:0-1 背包或最大团回溯时,进入左子树也冗余调用上界函数,或进入右子树忘记调用上界限界函数导致退化为暴力枚举
手工演算优先队列式分支限界法求解 0-1 背包 / 旅行商 TSP / 单源最短路 先按单位价值排序算线性松弛上界 \(ub\)(或 TSP 出边最小和下界 \(lb\));按大根堆(最大化问题)或小根堆(最小化问题)顺序列出每步弹出的扩展结点及生成的左右活结点状态表 ⚠ 避坑:活结点已装重量超容仍入队;或者当堆顶活结点的上界 \(ub \le bestv\) 时未及时剪枝终止
装载问题 / 最大团问题 / 图的 \(m\)-着色问题建模与复杂度分析 最大团:子集树,左剪枝看顶点 \(t\) 是否与当前团内所有点均有边相连,右剪枝看 \(cn + (n-t) > bestn\);\(m\)-着色:完全 \(m\) 叉树,总结点数 \(\frac{m^{n+1}-1}{m-1}\),时间 \(O(nm^n)\) ⚠ 避坑:把 \(m\)-着色问题的解空间树误当成子集树(应为度为 \(m\) 的完全 \(m\) 叉树)