人工智能公开课——04搜索:深度优先、爬山、束搜索

本文介绍了人工智能中的搜索算法,包括深度优先、广度优先、爬山搜索以及束搜索。深度优先通过回溯找到路径,广度优先逐层搜索可能路径但效率较低。爬山算法通过考虑节点与中点的距离改进了深度优先搜索。束搜索限制了每层的路径数量,提高了搜索效率。这些启发式搜索方法让算法更智能。

深度优先、广度优先

老师以一个地图的例子贯穿整节课讲解各种搜索算法。
如图所示:

我们的目标是从S开始到G,选择一条最优路径
老师介绍了两种搜索方式:深度优先和广度优先。
一、深度优先:不断向下进行路径的搜索,然后回到上层选择另一分支(backtracking)。用图表示:


最后,D往下到达了G,搜索结束。
二、广度优先:一层一层建立目标树,如图所示:

每完成一层的搜索横向扫描是否有G,在第三层扫描{C,G,D,E}的时候,发现的了G,故路径为S->A->D->G,搜索结束。

用队列的思想来表达的话,流程为:
小结:虽然深度优先算法和广度优先算法都能最终找到路径,但是我们可以发现,深度优先算法会经过很多次回溯,广度优先算法则是列举在找到最佳路径前所有的路径,这样的算法并不智能,程序运行的效率低,时间长。此外,老师利用发杂的路线程序距离,不同的扩展算法得到的最优路径也不同,并且有时候我们用直觉来看并不是最佳路径。为此引入扩展列表算法:除非末端节点从未被扩展过,我们才去扩展该节点。
如图所示:

<think>我们参考了多个引用,其中引用[1]提到最佳优先搜索(Best-First Search)是一种优先级遍历算法,常见于人工智能领域,如问题求解、规划和游戏。在迷宫寻路中,它用于寻找最短路径,但不保证最优解,因为它只选择当前最有希望的节点扩展。引用[2]讨论了贪婪最佳优先搜索(GBFS)和A*搜索的比较。引用[3]列举了多种路径规划算法,包括GBFS。引用[4]则抱怨了网上关于GBFS的资料混乱问题。引用[5]展示了一个使用最佳优先搜索算法寻找城市间路径的代码示例。 根据用户当前的问题“我想查找最佳优先搜索的具体算法”,我们需要给出最佳优先搜索(这里通常指贪婪最佳优先搜索)的具体算法步骤。 最佳优先搜索(Greedy Best-First Search, GBFS)是一种启发式搜索算法,它使用启发函数来评估当前节点到目标节点的估计代价(例如曼哈顿距离、欧几里得距离等),并总是选择启发函数值最小的节点(即最有希望接近目标的节点)进行扩展。 算法步骤: 1. 初始化:将起始节点放入开放列表(通常用优先队列实现,按启发函数值排序)。 2. 循环直到开放列表为空或找到目标节点: a. 从开放列表中取出启发函数值最小的节点(即最有可能接近目标的节点)作为当前节点。 b. 如果当前节点是目标节点,则回溯路径并返回成功。 c. 否则,将当前节点移出开放列表,放入封闭列表(表示已访问)。 d. 扩展当前节点,生成其所有邻居节点(或未访问的后继节点)。 e. 对于每个邻居节点: - 如果邻居节点已经在封闭列表中,则跳过。 - 如果邻居节点不在开放列表中,则将其加入开放列表,并记录其父节点(用于回溯路径)。 - 注意:GBFS不要求更新已存在于开放列表中的节点的代价,因为它不考虑从起点到当前节点的实际代价,只考虑当前节点到目标的估计代价。 3. 如果开放列表为空且未找到目标,则搜索失败。 注意:GBFS使用启发函数$h(n)$来估计从节点$n$到目标节点的代价。它总是选择$h(n)$最小的节点扩展。然而,由于它忽略了从起点到当前节点的实际代价$g(n)$,因此可能找到的不是最优解。 下面是一个伪代码示例: ``` function GBFS(start, goal): open_list = PriorityQueue() # 优先级队列,按h(n)排序 closed_list = set() # 将起始节点加入开放列表,其启发值h(start)由启发函数计算 open_list.put(start, h(start)) start.parent = None while not open_list.empty(): current = open_list.get() # 取出h(n)最小的节点 if current == goal: return reconstruct_path(goal) # 重构路径 closed_list.add(current) for neighbor in current.neighbors: if neighbor in closed_list: continue if neighbor not in open_list: neighbor.parent = current # 记录父节点 open_list.put(neighbor, h(neighbor)) return None # 搜索失败 ``` 重构路径的函数(从目标节点回溯到起始节点): ``` function reconstruct_path(node): path = [] while node is not None: path.append(node) node = node.parent return path.reverse() # 将路径反转成从起点到目标 ``` 需要注意的是,GBFS可能会陷入死循环(如果启发函数不够好),或者找到非最优路径。因此,在实际应用中,有时会结合其他策略,或者使用A*算法(综合考虑$g(n)$和$h(n)$)。 相关问题: 1. 贪婪最佳优先搜索算法为什么不能保证找到最优解? 2. 贪婪最佳优先搜索算法在什么情况下会表现良好? 3. 如何设计一个有效的启发函数? 4. 贪婪最佳优先搜索与A*搜索的主要区别是什么? </think>### 最佳优先搜索(Best-First Search)具体算法 最佳优先搜索(GBFS)是一种启发式搜索算法,其核心思想是**优先扩展距离目标最近的节点**。算法流程如下: #### 算法步骤 1. **初始化** - 创建优先级队列(开放列表),按启发函数值$h(n)$排序 - 将起始节点加入队列,记录$h(\text{start})$ 2. **主循环** ```python while 优先级队列非空: current = 队列中h(n)最小的节点 # 取出最有希望的节点 if current == 目标节点: 回溯路径并返回成功 # 找到解 将current移入封闭列表 for 每个相邻节点neighbor: if neighbor在封闭列表中: continue if neighbor不在开放列表中: 计算h(neighbor) # 启发函数评估到目标的距离 设置neighbor.parent = current 将neighbor加入开放列表 ``` 若队列为空则返回失败 3. **回溯路径** 从目标节点沿`parent`指针反向追溯至起点 #### 核心特点 1. **启发函数$h(n)$** - 估计节点$n$到目标的最小代价 - 示例:在路径规划中常用曼哈顿距离或欧氏距离 - 例如:$h(n) = \sqrt{(x_n-x_{\text{目标}})^2 + (y_n-y_{\text{目标}})^2}$ 2. **贪心策略** 始终选择当前$h(n)$最小的节点扩展(局部最优),但不考虑已累积路径代价 3. **数据结构** 使用优先级队列(通常是最小堆)实现高效取最小值 #### 算法缺陷(引用[2][4]) - ❌ **不保证最优解**:可能错过实际最短路径(忽略$g(n)$累积代价) - ❌ **易陷入局部最优**:尤其当启发函数不准确时 - ✔️ **高效性**:在启发函数有效时搜索速度优于BFS/DFS > 典型应用:罗马尼亚城市寻路问题(引用[5])、游戏AI路径规划(引用[1][3])。对比A*算法($f(n)=g(n)+h(n)$),GBFS缺少$g(n)$导致非最优性[^2][^3]。 --- ### 相关问题 1. 为什么贪婪最佳优先搜索不能保证找到最短路径? 2. 如何设计有效的启发函数来提高GBFS的搜索效率? 3. GBFS与A*搜索的核心区别是什么?哪种更适合实时路径规划? 4. 在迷宫寻路问题中,哪些情况下GBFS会优于广度优先搜索? 5. 如何通过混合搜索策略解决GBFS在大规模地图中的内存瓶颈?[^2] [^1]: 优先级遍历算法实现步骤描述 [^2]: 宽度优先搜索与迭代加深DFS的混合策略 [^3]: 路径规划算法对比(A*、GBFS、Dijkstra) [^4]: GBFS算法实现中的常见混淆问题 [^5]: 城市路径搜索的GBFS代码实例
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值