分枝界限法

回溯法:求出解空间中满足约束条件的所有解。

分支界限法:找出满足约束条件的一个解。

搜索方式:回溯法使用深度优先的方式,而分支界限法使用广度优先或最小耗费的方式搜索解空间。

1. 单源最短路径问题:

问题描述:在有向图中,求出源顶点 s 到 目的顶点的最短路径。

解决办法:使用优先队列式的分支界定法。

算法描述:

        1. 使用最小堆MinHeap来存储活结点列表,初始时MinHeap={ Node }, Node.indx = s,  Node.len = 0.
        2. 使用 dist[1...MaxNode] 来存储s到最各结点的最小距离,初始时 dist[1...MaxNode] = Inf, 但是 dist[s] = 0.
        3. 循环以下操作直到 MinHeap为空:
                    取MinHeap堆顶元素E.
                   针对 i = 1 ... MaxNode:
                            若 adj[ E.indx ][ i ] < Inf && E.len + adj[ E.indx ][ i ] < dist[ i ], 则:     // [这里是剪枝的条件]
                                      dist[ i ] = E.length + adj[ E.indx ][ j ]
                                      pre[ i ] = E.indx
                                      Node={"indx":i, "len":dist[i]}, 将Node 加入堆MinHeap中,  即扩展堆顶的结点。   
python 代码如下:








2. 0-1背包:

( 0-1背包的分枝界定算法法类似于A*算法。)

输入:N个物品重量、价值。 背包重量: W.

算法步骤:

         1. 计算出N个物品的单位价值,按单位价值排序。设排序后N个物品的重量: w1, w2, ..., wN;N个物品的价值:v1, v2, ..., vN。

         2. 设初始重量w=0, 初始价值v=0.

         3. 初始化最大堆的结点:{w=0,v=0, candidate_indx = 1, upbenefit = v + (W-w)*(v1/w1)}。

         4. 对于最大堆的堆顶( upbenefit 最大者在堆顶 )进行扩展:

                       设最大堆顶为:{w_cur, v_cur, candidate_indx, upbenefit }。

                       若:

                       a.  candidate_indx == N+1, 即堆顶为解空间树的叶子节点且目标函数值upbenefit最大,即求得最优解。

                       b. 若 w[ candidate_indx ] > W - w_cur, 即候选节点重量超出背包剩下容量, 放弃此堆顶。

                       c. 若 w [ candidate_indx ] <= W - w_cur, 扩展此候选节点:

                                         删除堆顶,将堆顶进行扩展 并 将扩展后的两个节点加入最大堆( upbenefit )中。

                                        1) 将candidate_indx 节点加入背包中:

                                             在堆中加一个节点:{ w_cur + w[ candidate_indx ], v_cur + v[ candidate_indx ], candidate_indx + 1, upbenefit = w_cur + w[ candidate_indx ] + (W-w_cur-w[candidate_indx]) * ( v[candidate_indx + 1] / w[candidate_indx] ) }

                                             即:将当前候选节点加入背包中,并计算背包的重量、价值、及 可能的最大值。

                                        2) 不加 candidate_indx 节点: 

                                             在堆中加一个节点:{ w, v, candidate_indx+1, v + (W-w)*( v[candidate_indx + 1] / w[candidate_indx] ) }

 上述算法中,upbenefit 为当前选择下,系统可能的最大价值。即已经选择物品的价值v + 未选择物品中单位价值最大值 x 剩余空间。

 堆中每个节点代表了一种背包方案。


示例:

假设有4个物品,其重量分别为(4, 7, 5, 3),价值分别为(40, 42, 25, 12),背包容量W=10。

其执行过程如下图所示:



上面的解空间树中:

w代表背包当前重量,v表示背包当前价值,ub代表在该节点代表的方案下背包最大可能价值。


python代码如下:







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 回溯求迷宫路径: 回溯求解迷宫路径的基本思路是从起点开始,尝试向不同方向走,如果某个方向可以走通,则继续向前探索;如果某个方向走不通,则回溯到上一个位置,尝试其他方向。具体实现可以使用递归算,代码如下: ```python def find_path(x, y, maze, path): # 判断当前位置是否越界或者是障碍物 if x < 0 or x >= len(maze) or y < 0 or y >= len(maze[0]) or maze[x][y] == 1: return False # 判断当前位置是否已经在路径中 if (x, y) in path: return False # 将当前位置加入路径 path.append((x, y)) # 判断当前位置是否是终点 if x == len(maze) - 1 and y == len(maze[0]) - 1: return True # 尝试向四个方向走 if find_path(x + 1, y, maze, path) or \ find_path(x - 1, y, maze, path) or \ find_path(x, y + 1, maze, path) or \ find_path(x, y - 1, maze, path): return True # 如果四个方向都走不通,则回溯到上一个位置 path.pop() return False # 测试代码 maze = [[0, 1, 0, 0], [0, 0, 0, 1], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]] path = [] find_path(0, 0, maze, path) print(path) ``` 2. 分枝界限求迷宫路径: 分枝界限求解迷宫路径的基本思路是将搜索空间划分为多个子空间,每个子空间对应一条路径,然后依次对每个子空间进行搜索,直到找到一条可行路径。具体实现可以使用队列或者堆栈保存待搜索的子空间,每次从队列或者堆栈中取出一个子空间进行搜索,直到找到一条可行路径或者队列或者堆栈为空。代码如下: ```python from queue import PriorityQueue def find_path(maze): # 定义一个优先队列,用于保存待搜索的子空间 queue = PriorityQueue() queue.put((0, [(0, 0)])) while not queue.empty(): # 取出一个子空间进行搜索 _, path = queue.get() x, y = path[-1] # 判断当前位置是否是终点 if x == len(maze) - 1 and y == len(maze[0]) - 1: return path # 尝试向四个方向走 for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]: nx, ny = x + dx, y + dy # 判断新位置是否越界或者是障碍物 if nx < 0 or nx >= len(maze) or ny < 0 or ny >= len(maze[0]) or maze[nx][ny] == 1: continue # 判断新位置是否已经在路径中 if (nx, ny) in path: continue # 计算新路径的代价(这里用路径长度作为代价) new_path = path + [(nx, ny)] cost = len(new_path) # 将新子空间加入优先队列 queue.put((cost, new_path)) return None # 测试代码 maze = [[0, 1, 0, 0], [0, 0, 0, 1], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]] path = find_path(maze) print(path) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值