元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-24 22:12
↑
☰
# 分支限界法 分支限界法(Branch and Bound)是一种用于求解最优化问题的算法思想。它通过系统地设置界限,剪除不可能包含最优解的分支,从而在解空间中搜索问题的解。 ## 基本概念 分支限界法的特点: 1. 分支:将问题分解为若干子问题 2. 界限:计算子问题的界限 3. 剪枝:去除不可能含最优解的分支 4. 搜索:按照特定策略搜索解空间 ## 核心思想 1. 分支策略 - 将问题分解为子问题 - 构建问题的解空间树 2. 界限函数 - 计算子问题的界限 - 判断是否需要继续搜索 3. 搜索策略 - 广度优先搜索 - 最小耗费优先 ## 实现方法 ### 1. 0-1背包问题 ```go // 使用分支限界法解决0-1背包问题 type Item struct { weight int value int } type Node struct { level int value int weight int bound float64 } func knapsack(items []Item, capacity int) int { n := len(items) queue := make([]Node, 0) // 计算单位重量价值,用于计算上界 valuePerWeight := make([]float64, n) for i := 0; i < n; i++ { valuePerWeight[i] = float64(items[i].value) / float64(items[i].weight) } // 初始节点 root := Node{level: -1, value: 0, weight: 0} root.bound = bound(root, items, capacity, valuePerWeight) queue = append(queue, root) maxValue := 0 for len(queue) > 0 { // 取出队首节点 current := queue[0] queue = queue[1:] // 跳过不可能产生更好解的节点 if current.bound <= float64(maxValue) { continue } // 尝试放入下一个物品 level := current.level + 1 if level >= n { continue } // 不放入当前物品 node1 := Node{ level: level, value: current.value, weight: current.weight, } node1.bound = bound(node1, items, capacity, valuePerWeight) if node1.bound > float64(maxValue) { queue = append(queue, node1) } // 放入当前物品 if current.weight + items[level].weight <= capacity { node2 := Node{ level: level, value: current.value + items[level].value, weight: current.weight + items[level].weight, } node2.bound = bound(node2, items, capacity, valuePerWeight) if node2.bound > float64(maxValue) { queue = append(queue, node2) } if node2.value > maxValue { maxValue = node2.value } } } return maxValue } // 计算上界 func bound(node Node, items []Item, capacity int, valuePerWeight []float64) float64 { if node.weight >= capacity { return 0 } result := float64(node.value) j := node.level + 1 totWeight := node.weight // 尽可能多地装入剩余物品 for j < len(items) && totWeight + items[j].weight <= capacity { totWeight += items[j].weight result += float64(items[j].value) j++ } // 装入最后一个物品的一部分 if j < len(items) { result += float64(capacity-totWeight) * valuePerWeight[j] } return result } ``` ### 2. 旅行商问题 ```go // 使用分支限界法解决旅行商问题 type TSPNode struct { level int path []int bound float64 cost float64 } func tsp(graph [][]float64) ([]int, float64) { n := len(graph) queue := make([]TSPNode, 0) // 初始节点 root := TSPNode{ level: 0, path: []int{0}, cost: 0, } root.bound = tspBound(root, graph) queue = append(queue, root) minCost := math.Inf(1) bestPath := make([]int, 0) for len(queue) > 0 { current := queue[0] queue = queue[1:] if current.bound >= minCost { continue } if current.level == n-1 { // 回到起点的成本 totalCost := current.cost + graph[current.path[n-1]][0] if totalCost < minCost { minCost = totalCost bestPath = make([]int, len(current.path)) copy(bestPath, current.path) } continue } // 尝试访问未访问的城市 for i := 1; i < n; i++ { if !contains(current.path, i) { newPath := make([]int, len(current.path)) copy(newPath, current.path) newPath = append(newPath, i) node := TSPNode{ level: current.level + 1, path: newPath, cost: current.cost + graph[current.path[current.level]][i], } node.bound = tspBound(node, graph) if node.bound < minCost { queue = append(queue, node) } } } } return bestPath, minCost } // 计算TSP的下界 func tspBound(node TSPNode, graph [][]float64) float64 { n := len(graph) bound := node.cost // 对于已访问的路径,使用实际成本 // 对于未访问的城市,使用它们连接其他城市的最小成本 visited := make(map[int]bool) for _, city := range node.path { visited[city] = true } // 添加未访问城市的最小出边 for i := 0; i < n; i++ { if !visited[i] { minEdge := math.Inf(1) for j := 0; j < n; j++ { if i != j && graph[i][j] < minEdge { minEdge = graph[i][j] } } bound += minEdge } } return bound } func contains(slice []int, item int) bool { for _, v := range slice { if v == item { return true } } return false } ``` ## 应用场景 1. 组合优化 - 背包问题 - 旅行商问题 - 作业调度 2. 资源分配 - 任务分配 - 设备调度 - 路径规划 3. 决策问题 - 投资决策 - 生产计划 - 网络流量 ## 优缺点 ### 优点 1. 效率高 - 有效剪枝 - 避免无效搜索 2. 解的质量 - 保证最优解 - 可提供界限 3. 适用性广 - 多种问题 - 灵活应用 ### 缺点 1. 内存消耗 - 需要存储状态 - 空间复杂度高 2. 界限计算 - 需要好的界限函数 - 计算开销大 ## 实践建议 1. 问题建模 - 合理分解问题 - 设计状态表示 2. 界限函数 - 选择合适的界限 - 平衡精度和效率 3. 搜索策略 - 选择合适的策略 - 优化搜索顺序 ## 总结 分支限界法是一种重要的优化算法: 1. 通过分支和界限有效剪枝 2. 适合求解组合优化问题 3. 需要合理设计界限函数 在实际应用中,需要根据具体问题特点,设计合适的分支策略和界限函数,并注意优化实现以提高效率。同时,要考虑问题规模和资源限制,在某些情况下可能需要使用启发式方法来获得近似解。