kyrie
kyrie
发布于 2025-11-04 / 30 阅读
0
0

回溯法和分支界限法

回溯法(Backtracking)

把问题的“决策过程”当成一棵状态空间树,按深度优先往下试探:做一个选择→继续→不行就撤销(回溯)。
核心是“剪枝”:一旦发现当前部分解违反约束(不可能继续得到可行解),立刻停止扩展这条路径。

  • 目标:通常是找可行解(一个、多个或全部),也可带最优性但以可行性剪枝为主。

  • 剪枝依据:

    • 约束函数:立刻判定“冲突/超界/重复”等非法。

    • (可选)限界估计:给当前前缀能达到的最好成绩做个乐观估计,用来提前止损。

  • 搜索策略:DFS/递归/栈,先走到底再回头。

伪代码

best = -∞ 或 收集 = ∅
DFS(node):
  if 违反约束: return
  if 到达叶子(形成完整解):
      更新 best 或 收集解
      return
  for 每个可选决策:
      选择
      // 可选:做乐观估计,若“最乐观也不如 best”则剪枝
      DFS(后继)
      撤销选择

分支限界法(Branch and Bound, B&B)

同样沿状态空间树搜索,但面向优化问题:每个结点计算一个界(上界或下界),若这个界也不可能优于当前最优解,就直接丢弃整棵子树

  • 目标:全局最优解

  • 关键:界的设计要“乐观但不犯错”(最大化用上界≥真实最优,最小化用下界≤真实最优)。

  • 结点选择:不必 DFS,可用

    • 队列(FIFO 分支限界,近似 BFS),

    • 优先队列(Best-first / LC 分支限界,按界值挑最有希望的结点),

    • 也可用栈(DFS),但通常配合更强的界。

伪代码

best = -∞(最大化); PQ 以 bound 降序
根结点入队(算好 bound)
while PQ 非空:
  取出 bound 最大的结点 u
  if u.bound ≤ best: continue      // 不可能更优,丢
  扩展 u 的孩子 v:
      计算 v.bound
      if v 是完整可行解:
          best = max(best, v.value)
      else if v.bound > best:
          PQ.push(v)
返回 best

例题(01背包)

回溯法

伪代码

best = 0, best_x = []
DFS(i, curW, curV):                 // 已决策到第 i 件(1..n),累积重量/价值
  if curW > C: return               // 约束函数:超重剪枝
  if i > n:
      if curV > best: best = curV; best_x = 当前选择
      return
  // 选 i
  选[i] = 1
  DFS(i+1, curW + w[i], curV + v[i])
  // 不选 i
  选[i] = 0
  DFS(i+1, curW, curV)

搜索解空间树

分支界限法

约束函数 C(i) :到第 i 层的剩余容量

C(i)=C-\sum_{k=1}^{i}x_k w_k \quad(\text{若 }C(i)<0\text{ 则剪枝})

限界函数 B(i):对“尚未决定的物品”用分数背包给出乐观上界
(先按价值密度 v_j/w_j 从大到小装满,最后一件可取分数)。

本例密度: 1号:35/15\approx2.332、3号=2.0。顺序 1\rightarrow2\rightarrow3

伪代码

预处理:

// 将物品按价值密度从大到小重排(仅用于计算上界与/或决策顺序)
reorder items so that ρ1 ≥ ρ2 ≥ ... ≥ ρn
// 若不想重排决策顺序,也可以单独保留一个密度序 p[1..n] 专供上界函数遍历

function UPPER_BOUND(i, curW, curV):
    // 估计:从第 i 件开始,用“分数背包”把剩余容量装满,得到乐观上界
    if curW > C: return curV           // 已经超重,返回当前值(也可返回 -∞)
    rem = C - curW
    ub  = curV
    for k = i .. n:                    // 遍历密度降序后的物品
        if w[k] <= rem:
            ub  = ub + v[k]
            rem = rem - w[k]
        else:
            ub  = ub + ρ[k] * rem      // 允许最后一个取“分数”
            break
    return ub

DFS分支界限:

global best = 0
global best_x[1..n] = 0

procedure DFS(i, curW, curV, x[1..n]):
    ub = UPPER_BOUND(i, curW, curV)
    if curW > C: return                          // 约束剪(超重)
    if ub <= best: return                        // 界剪(最乐观也不可能更优)

    if i > n:                                    // 到达叶子(一个完整可行解)
        if curV > best:
            best = curV
            best_x = x
        return

    // 分支1:选择第 i 件
    x[i] = 1
    DFS(i + 1, curW + w[i], curV + v[i], x)

    // 分支2:不选第 i 件
    x[i] = 0
    DFS(i + 1, curW, curV, x)

procedure BnB_DFS(w[1..n], v[1..n], C):
    // 可选:按密度重排 w,v(或保留单独的密度序供 UPPER_BOUND 使用)
    best = 0; best_x = all zeros
    x = all zeros
    DFS(1, 0, 0, x)
    return best, best_x

搜索空间树


评论