【算法分析】分支限界法 一般方法

文章介绍了分支限界算法与回溯算法的区别,强调分支限界法采用BFS策略。LC检索通过成本函数优化搜索过程,每次选择成本最小的节点扩展。15迷问题作为示例说明LC检索的应用,同时讨论了估计函数在优化搜索路径中的作用。文章指出,当估计函数准确反映实际成本时,LC检索能有效找到最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

分支限界算法类似于回溯算法。区别是回溯算法进行dfs搜索,而分支限界法进行bfs搜索。

过程:生成当前E节点的全部儿子之后,才从活结点表中选择下一个活结点作为新的E节点。(BFS,可以想想二叉树层序遍历的例子)

活结点:自己已经生成,但是儿子还没开始生成。

E节点:正在扩展的节点。

死节点:儿子节点已经全部生成。

分支限界法的活结点表:FIFO(队列)、LIFO(堆栈)

但是只有这两种活结点表过于死板。比如dfs的下一步就是答案了,但是bfs还要把当前层都扫完才能取下一层找到答案。所以引出了LC检索来优化这个问题。

二、LC-检索(least cost最低成本)

每次把当前节点的子节点放到活结点表中,每次按照成本函数取出成本最小的节点继续拓展。

(具体结合下面的15迷问题来理解LC检索的过程,以及估计函数的定义)

给出一个带有智力的排序函数来决定出当前活结点表中的优先权。(这和棋类游戏中的评估函数很像,对于当前局面给出一个评分)

如果假设我们已经知道答案了,根据答案定义了一个C(x)函数。

### 分支限界法解决01背包问题的算法分析 #### 背包问题描述 给定一组物品,每种物品具有一定的重量 \( w_i \) 和价值 \( p_i \),以及一个最大承重为 \( M \) 的背包。目标是从这些物品中选取若干个放入背包,使总重量不超过 \( M \),并最大化总价值。 #### 解空间结构 对于每个物品而言,存在两种状态:被选入背包或未被选入背包。因此,整个解空间可以表示为一棵二叉树,其中左子节点代表当前物品被选入背包的状态,右子节点代表当前物品未被选入背包的状态[^1]。 #### 剪枝策略 为了减少不必要的计算,在遍历过程中采用剪枝操作来排除不可能成为最优解的部分: - **可行性约束**:如果某个部分解对应的累计重量已经超过了背包的最大承载能力,则可以直接舍弃这条路径及其后续的所有可能扩展。 - **界限函数**:通过估计剩余可获得的最大收益来进行进一步裁减。具体来说,当到达某一层级时,可以根据已知条件预测继续向下发展所能达到的最佳结果。如果这个预估值低于目前已知最佳解决方案的成绩,则无需再深入探索此分支[^2]。 例如,在结点2处,将物品1装入背包后,当前背包重量变为4,获取到的价值为40元。此时还可以装载的空间大小为\( 10 - 4 = 6\) 单位质量,假设单位质量对应的价值密度保持不变的话,理论上最多还能增加额外约\( 6 * 6 = 36 \) 元的价值量,那么总的潜在价值上限即为\( 40 + 36 = 76 \)[^3] 。 如果这一数值小于目前记录下来的全局最高分值,则没有必要再去考察该方向上的其他可能性了。 #### 实现细节 以下是基于上述原理的一个简单实现版本(伪代码形式),展示了如何利用队列数据结构配合优先级机制完成搜索过程: ```python from queue import PriorityQueue def branch_and_bound(weights, values, capacity): n = len(weights) class Node: def __init__(self, level, profit, weight, bound): self.level = level # 当前层数/正在考虑第几个物品 self.profit = profit # 已经累积得到的利益总额 self.weight = weight # 当前所占用的质量总量 self.bound = bound # 上界估算 def __lt__(self, other): # 定义比较规则以便于维护堆序关系 return self.bound > other.bound max_profit = 0 # 记录最终答案 pq = PriorityQueue() # 初始化优先队列用于存储候选节点信息 u = Node(-1, 0, 0, calculate_bound(n, weights, values, capacity)) # 创建根节点 pq.put(u) while not pq.empty(): u = pq.get() if u.bound >= max_profit: # 只有当上界大于等于现有最好成绩才值得继续尝试 v = Node(u.level + 1, u.profit + values[u.level], u.weight + weights[u.level], calculate_bound(u.level+1,weights[:u.level]+values[:u.level],capacity-u.weight)) if v.weight <= capacity and v.profit > max_profit: # 更新最大利润 max_profit = v.profit if v.bound >= max_profit: # 加入新的叶节点至活节点列表 pq.put(v) w = Node(u.level + 1,u.profit,u.weight, calculate_bound(u.level+1,weights[:u.level]+values[:u.level],capacity-u.weight)) if w.bound >= max_profit: # 同样地处理另一侧情形 pq.put(w) return max_profit def calculate_bound(level, remaining_weights,remaining_values,capacity_left): total_weight = sum(remaining_weights[level:]) total_value = sum(remaining_values[level:]) ratio = min(total_value /total_weight , capacity_left/(sum([w for w in remaining_weights[level:]if w<=capacity_left]))) return int(ratio*sum(remaining_weights[level:])+(level<length)*remaining_values[level]) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值