奇怪的搜索技巧:优化搜索

奇怪的搜索技巧:优化搜索

这次的内容预告:迭代加深、A*、IDA*、极大极小搜索法、跳舞链。


零、前置:dfs的最优性剪枝

比最优解要劣就退出。

一、迭代加深dfs

当搜索深度达到约束值却还没找到可行解时结束搜索。如果我们在一个深度约束下没有搜索到答案,那么答案一定在更深的位置,那么就把约束深度调整到更深,然后再次搜索,直到搜索到答案为止。

估价函数:在实际运用中,如果没有一个合适的方法来剪枝,迭代加深搜索也会很容易超时。好在迭代加深搜索有一个比较特殊的剪枝方法,就是对当前的情况通过一个乐观估计函数进行预估,如果发现即使在最好的情况下搜索到当前的最深深度限制也没办法得到答案,那么就及时退出来实现剪枝。这个其实叫做可行性剪枝。也是下文的IDA*。

二、A*

优化优先队列bfs。这里真正要用到上面提到的估价函数。这里有个要求:设当前状态 u u u到目标估计值 f ( u ) f(u) f(u),实际得出 g ( u ) g(u) g(u),必须满足 f ( u ) < g ( u ) f(u)<g(u) f(u)<g(u)。即估计值是更优的。

这个算法的关键就在于设计优秀的估价函数。

三、IDA*

考虑优化迭代加深的dfs,利用和A* 一样的思路。A* 的思路有一个缺陷,空间消耗大而且每次对堆操作花费 O ( log ⁡ n ) O(\log n) O(logn)时间。所以对迭代加深dfs拓展成类似A* 的形式就是IDA*。

关键点来了:综合一下迭代加深和A*,得出限制:若当前深度+未来估计步数>深度限制,就回溯。

练习:

P1379 八数码难题

P4467 [SCOI2007]k短路

P2324 [SCOI2005]骑士精神


四、极大极小搜索法 与 Alpha-Beta剪枝

适用范围:博弈题。

博客推荐

极大极小搜索法:正方形代表自己的选择,圆形代表对方的选择。每个节点表示对我的利益值。正方形的值即为儿子中最大值,圆形为儿子中最小值。

B总是选择候选方案中的最小值,而A总是选择候选方案中的最大值,极小极大的名字也就源于此。该算法使用深度优先搜索(Depth First Search)遍历决策树来填充树中间节点的利益值,叶子节点的利益值通常是通过一个利益评估函数计算。

Alpha-Beta剪枝:假设α为下界,β为上界,对于α ≤ N ≤ β:
若 α ≤ β 则N有解。 若 α > β 则N无解。初始设置α为负无穷大,β为正无穷大。 每次回溯的时候,父亲节点的α或β值进行修改即可。这样就可以剪掉很多无用状态。

练习:POJ 1085 三角点格棋


五、跳舞链(Dancing Links)

适用问题:求解精确覆盖问题

博客推荐

博客推荐

主要是通过新建双向链表来完成回溯。

可以把Dancing Links的求解过程表述如下

  1. Dancing函数的入口
  2. 判断Head.Right=Head?,若是,输出答案,返回True,退出函数。
  3. 获得Head.Right的元素C
  4. 标示元素C
  5. 获得元素C所在列的一个元素
  6. 标示该元素同行的其余元素所在的列首元素
  7. 获得一个简化的问题,递归调用Daning函数,若返回的True,则返回True,退出函数。
  8. 若返回的是False,则回标该元素同行的其余元素所在的列首元素,回标的顺序和之前标示的顺序相反
  9. 获得元素C所在列的下一个元素,若有,跳转到步骤6
  10. 若没有,回标元素C,返回False,退出函数。

练习

P4929 【模板】舞蹈链(DLX)

### Dijkstra算法的特殊优化技巧 #### 使用斐波那契堆减少时间复杂度 传统实现中,Dijkstra算法使用二叉堆来管理节点优先级队列。然而,通过采用更高效的斐波那契堆数据结构可以进一步降低更新操作的时间开销。具体来说,在处理大规模图时,这种改进能够显著提高性能[^1]。 ```python import heapq def dijkstra_with_fibonacci_heap(graph, start): fib_heap = FibonacciHeap() distances = {node: float('inf') for node in graph} previous_nodes = {node: None for node in graph} distances[start] = 0 entry_finder = {} # 初始化最小堆 for vertex in graph: if vertex == start: entry_finder[vertex] = fib_heap.insert(0, vertex) else: entry_finder[vertex] = fib_heap.insert(float('inf'), vertex) while not fib_heap.is_empty(): current_distance, u = fib_heap.extract_min() for neighbor, weight in graph[u].items(): distance_through_u = current_distance + weight if distance_through_u < distances[neighbor]: old_entry = entry_finder[neighbor] new_entry = (distance_through_u, neighbor) fib_heap.decrease_key(old_entry, *new_entry) distances[neighbor] = distance_through_u previous_nodes[neighbor] = u return distances, previous_nodes ``` #### 动态调整启发式函数加速收敛速度 尽管严格意义上讲这不是对原始Dijkstra算法本身的修改,但在某些应用场景下引入合适的启发式估计可以帮助更快找到最短路径。例如A*搜索就是在Dijkstra基础上加入了基于目标位置的距离作为额外指导信息[^2]。 当仅需计算特定两点间距离而非全局最短路时,这种方法特别有效: - 对于平面直角坐标系中的点,可选用曼哈顿距离或欧几里得距离; - 如果地图存在障碍物,则应考虑实际通行成本构建更加精确的成本模型; 需要注意的是,为了保持解的最优性,所选启发式的估值不应超过真实代价——即满足一致性条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值