人工智能(第3版) 第二章—学习笔记
2.0 简介:智能系统中的搜索
这一部分内容简单的列举了我们生活中出现的一些常见的搜索问题,并简单介绍了本章之后需要学习的状态分析图,生成——测试搜索范式,盲目搜索算法,贪心算法和回溯法等内容。
2.1 状态空间图
状态空间图(state-space graph)是对问题的一种表示方法,将某个具体问题的解对应为状态空间图中的一条路径,使人们可以根据空间图探索和分析通往解的可能的可选路径。
假币问题
有 12 枚硬币,已知其中一枚是假的,但是不知道这枚假币比真币轻还是重。普通的天平可以用于比较任意两组硬币的质量。可以找到一个方法,只需要称三次(每次对两组硬币进行比较),就可以找出那枚假币。
微型假币问题:只涉及6枚硬币,其他条件不变。
抽象:在求解过程中,忽略某些与结果明显无关的细节,在合理的层面思考与解决问题。
状态空间树:
状态空间树由节点和分支组成。每个椭圆是一个节点,代表问题的一个状态。节点之间的弧表示将状态空间树移动到新节点的运算符(或应用该运算符的结果)。
问题的状态空间树包含了问题可能出现的所有状态以及这些状态之间所有可能的转换。问题的解通常需要在这个结构中进行搜索(无论它是树还是图),搜索始于起始节点或起始状态,止于终点或目标状态。
**解的代价 **指到达目标状态所需的运算符的数量,而不是实际找到此解所需的工作量。
通常情况下,状态空间图可以包含代表相同问题状态的多个节点。(达到相同结果的不同路径)
2.2 生成-测试范式
是问题求解的一种直接方式,即先给出可能的解,再检查每个可能的解,看是否有候选解能够构成问题的解。
n 皇后问题
指的是将 n 个皇后放置在一个 n×n 的棋盘上,任何两个皇后都不占据相同的行、列或对角线。这些条件被称为问题的约束条件。
- 如果生成器给出了每个可能的解,那么该生成器是完备的。
- 如果生成器给出的解是不重复的,那么该生成器是非冗余的。
- 如果生成器有一些信息,允许其对给出的解做出一些限制,那么该生成器是知情的。
过程大概如下:
{While 没有找到解,但仍有候选方案
[生成可能的解
测试其是否满足所有的问题约束条件]
End While}
IF 找到某个解,则宣布成功,并输出此解
Else 宣布没有找到解
2.2.1 回溯法
部分解:只解决了一部分问题的解。
完全枚举法:它会查看所有情况以寻找问题的解,甚至在已经发现当前步骤不可能成功得到解的情况下,还可能从部分解开始进一步往后搜索,这要求测试者在每一步给出部分解后,都要检查以保证问题的约束条件没有被违反。
回溯法:将搜索分成多个步骤的搜索过程,每一步都会按照规定的方式做出选择。如果问题的约束条件得到满足,那么搜索将进行到下一步。如果任何选择都得不到可行的部分解,那么搜索将回溯到前一步,撤销前一步的选择,继续下一个可能的选择结果。
2.2.2 贪心算法
先将一个问题分成几个步骤进行求解,其中每次只考虑一个输入。贪心算法总是包含一个必须优
化(即最大化或最小化)的目标函数。
贪心算法在每一步选择中都采取当前情况下最好或最优的选择,从而希望追求当下的结果是最好或最优的,但不会考虑整体的最佳结果。
使用贪心算法求解问题的效率很高,但遗憾的是,计算机科学中的一些问题并不能使用这种范式来求解。
2.2.3 旅行商问题
在旅行商问题(也称旅行销售员问题)中,给定 n 个顶点的加权图(即每条边上带有开销值),求从某个顶点 Vi出发经过加权图中的所有顶点(每个顶点只经过一次),然后返回到 Vi的最短路径。(即需要寻找最短的回路)
分支定界算法(也称统一代价搜索)是广度优先搜索的一种变体。在这种搜索算法中,节点按照开销不减少的原则进行探索,可以成功解决旅行商问题。
2.3 盲目搜索算法
盲目搜索算法是不使用问题域知识的不知情搜索算法。这些算法假定不知道状态空间的任何信息。
3 种主要的盲目搜索算法如下:深度优先搜索(DFS)、广度优先搜索(BFS) 和迭代加深的深度优先搜索(DFS-ID)。
这些算法都具有如下两个性质:
- 它们不使用启发式估计。如果使用启发式估计,那么搜索将沿着最有希望得到解的路径前进。
- 它们的目标是找出给定问题的某个解。
2.3.1 深度优先搜索
深度优先搜索(DFS),是试图尽可能快地深入树中进行搜索。每当搜索方法可以做出选择时,就选择最左(或最右)分支(通常选择最左分支)。
避免重复状态是许多高效搜索算法的基本特征。
2.3.2 广度优先搜索
广度优先搜索(BFS),以从左到右(或从右到左,不过从左到右更常见)的方式,可以逐层访问节点。必须首先访问第 i层的所有节点,然后才能访问第 i +1 层的节点。
传教士与野人问题
2.4 盲目搜索算法的实现和比较
DFS 要求尽快地深入状态空间图,而 BFS 在进入下一层之前,先遍历了从根开始算起指定距离内的所有节点。
2.4.1 深度优先搜索的实现
所有搜索算法都需要维护两张表:开放表和封闭表。
开放表中包含了树中所有待探索(或扩展)的节点,而封闭表中则包含了所有已探索和不再考虑的节点。
DFS 的搜索过程通过栈结构维护开放表来实现。栈是一种后进先出(LIFO)的数据结构。某个节点一旦被访问,就被移到开放表的头部,以确保下一次能生成其子节点。
2.4.2 广度优先搜索的实现
广度优先搜索则探索靠近根的所有节点,然后才深入探索搜索树。
广度优先搜索用队列来表示开放表。队列是一种先进先出(FIFO)的数据结构。一旦节点被扩展,其子节点就会移动到开放表的尾部。因此,只有在其父节点所在层中的每个其他节点都被访问之后,才会访问这些子节点。
2.4.3 问题求解性能的衡量指标
完备性
当问题存在解时,如果搜索算法可以保证找到一个解,就说这个算法是完备的(complete)
最优性
果搜索算法能提供所有解中那个开销最低的解,则认为这个算法是最优的(optimal)。
时间复杂度
搜索算法的时间复杂度(time complexity)关注的是找到解需要花费的时间。这里可以根据搜索期间生成(或扩展)的节点数量来衡量时间
空间复杂度
搜索算法的空间复杂度(space complexity)关注的是内存开销。我们必须确定存储到内存中的最大节点数目。
AI 中的复杂度是用如下 3 个参数表示的:
- 节点的分支因子(branching factor,记为 b),指的是从节点出发的分支数(见图 2.31)。
- 参数 d 给出的是最浅目标节点的深度。
- 参数 m 给出的是状态空间中所有路径的最大长度。
如果某棵搜索树中的每个节点的分支因子都是 b,那么这棵搜索树的分支因子也等于 b。
2.4.4 DFS 和 BFS 的比较
在下列情况下,优选深度优先搜索。
- 树很深。
- 分支因子不太大,并且 解出现在树中的位置相对较深。
如果是以下情况,则优选广度优先搜索。
- 搜索树的分支因子不太大(一个适度的 b 值)。当整棵树的分支因子实际上很大时,BFS 会因为有过多的路径需要探索而不堪重负。
- 解出现在树中的位置在合理的深度(一个适度的 d 值),并且所有路径都不是特别深。
深度优先搜索具有中等的存储空间需求,而广度优先搜索的空间复杂度是指数解的。结合 DFS 的中等存储空间需求,去除寻找长路径的倾向,可以得到迭代加深的 DFS,即 DFS-ID(DFS With Iterative Deepening)
DFS-ID
DFS-ID 执行一个 DFS 算法,其状态空间的深度的界为 0,如果没有找到目标,就执行另一个 DFS 算法,此时深度的界为 1。继续以这种方式搜索,在每次迭代中,深度的界都会增加 1。在每次迭代中,一个完备的 DFS 都要执行到当前深度。在每次迭代中,搜索都要重新开始。
每一棵树都是从头开始绘制的。没有任何一棵树是从深度的界比其小 1 的树上建立起来的。
当分支因子有限时,与 BFS 一样,DFS-ID 是完备的。当路径开销是节点深度的非递减函数时,DFS-ID 是最优的。