0
点赞
收藏
分享

微信扫一扫

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)


文章目录

  • ​​1 基于目标的agent​​
  • ​​1.1 问题形式化​​
  • ​​2 基本概念与知识​​
  • ​​3 图搜索​​
  • ​​4 搜索树中节点的数据结构​​
  • ​​5 选择队列来存储边缘集合​​
  • ​​6 不同策略的评价指标​​
  • ​​7 无信息搜索​​
  • ​​7.1 cost一样的BFS示例​​
  • ​​7.2 cost一样的DFS示例​​
  • ​​7.3 cost不一样的BFS示例​​
  • ​​7.4 cost不一样的DFS示例​​
  • ​​7.5 UCS示例​​
  • ​​7.6 深度受限搜索DLS​​
  • ​​8 有信息(启发式)搜索​​
  • ​​8.1 GBF示例​​
  • ​​8.2 A\*算法示例1​​
  • ​​8.3 A\*算法示例2​​

1 基于目标的agent

使用【基于目标的agent】来通过搜索解决问题并求得问题的解,而问题的解是由初始节点到目标节点的行动序列。

1、定义要求解的问题分为两步:问题形式化与目标形式化,前者将问题进行形式化,后者定义具体要实现什么目标。

2、解决要求解的问题也分为两步:搜索与执行,前者通过在内心中推演或通过画图、计算等方式进行探索,后者执行已找到的解。

1.1 问题形式化

  • 初始状态:agent开始时的状态。
  • 状态:从初始状态开始,由任何行动序列可到达的状态,所有状态构成状态空间。
  • 行动:agent可实现的行动。如在状态s下,Action(s)返回能从状态s下执行的行动集合,所有行动构成行动空间。
  • 转移模型:描述在状态s下执行每一个行动a后得到的结果,Result(s,a)。
  • 目标测试:判断某一给定状态是否为目标状态。
  • 路径耗费:为一个函数,是对某一条行动序列的性能度量,通常是将某个数值当作成本/耗费,如耗费时间大小、距离大小等。

2 基本概念与知识

状态空间:指一个物理/现实的环境。

搜索空间:指一个由【可能符合条件的解构成的搜索树或搜索图】表示的抽象的环境。搜索空间划分为以下三部分:

  • 1、边缘集合(Frontier)存放的是未扩展的(也就是叶子)节点。也称为Open List。
  • 2、已扩展集合(Explored)存放的是已扩展的节点。也称为Closed List。
  • 3、未扩展集合(Unexplored)存放的是未被扩展的节点。

搜索策略的核心就是将节点从集合3移到集合1,最后移到集合2。搜索策略的不同决定了移动顺序的不同。

除此之外还有一个,重复状态集合(Repeated)存放的是重复生成的节点。

搜索树:构建行动的序列。

  • :即初始状态。
  • 连线与箭头:代表行动。
  • 节点:节点有父节点、子节点、深度值、路径耗费大小,这些与状态空间中的每个状态都有关联。

扩展方案(搜索策略):本质是一种/个函数,它给出了从上一节点到子节点的【选择】方案。

3 图搜索

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI

图搜索算法构建的搜索树中,每个节点(即状态)最多出现一次,因此可以认为搜索树是【直接根据状态空间图】构建的。而且图搜索算法的好处是边缘集合(Frontier)将直接状态空间图分成两部分:已探索集合(Explored)与未探索集合(Unexplored)。

4 搜索树中节点的数据结构

搜索算法需要一种数据结构,用来记录构建搜索树的过程。对于树中的每一个节点n,这样的数据结构包含四部分:

  • 状态(state):节点n对应于状态空间中的哪一个状态。
  • 父节点(parent):搜索树中生成节点n的父节点。
  • 行动(action):父节点在生成节点n时采取的行动。
  • 路径耗费(cost):耗费用g(n)表示,大小为【从初始节点到节点n】的路径耗费。

在给定父节点的这四部分数据结构后,便可以方便地计算子节点对应的四部分数据结构。

注意:节点与状态的区别:节点是搜索树的一种数据结构,数据结构中包括四个值:该节点对应的状态state、该节点的父节点parent、该节点的父节点在产生该节点时的行动action和从初始节点到该节点所用的路径耗费cost。而状态对应于现实世界的环境状态。

另外,注意,同一状态可能通过两条不同的搜索路径由两个不同的节点生成。

5 选择队列来存储边缘集合

边缘集合需要以一种【能根据指定的搜索策略,让搜索算法易于选择下一步哪个节点该被扩展】的存储方式来存储未扩展的节点。最合适的数据结构是【队列】。

在队列中,有以下三种操作:

  • 判断队列是否为空:Empty(queue)。若队列中没有元素就返回True。
  • 弹出元素:Pop(queue)。弹出并移除(Remove)队列的第一个元素。
  • 插入元素:Insert(element, queue)。在队列中插入一个元素然后返回变化后的队列。

队列的特征是可以记录插入队列的元素的顺序(Order)。有以下三种队列:

  • FIFO queue,(普通)队列。先进先出,每次Pop队列中的第一个进入队列(即存在时间最长)的节点。
  • LIFO queue,栈。后进先出,每次Pop队列中的最后一个进入队列(即存在时间最短)的节点。
  • Priority queue,优先级队列。根据某种排序算法,计算队列中每个节点的优先级大小,每次Pop队列中优先级最高的节点。

6 不同策略的评价指标

不同的搜索策略由扩展节点的顺序所区别。即两个策略的不同指的是扩展节点顺序的方法不同。

搜索策略的评价指标

  • 完备性。有解时总是能找到解吗?
  • 最优性。总能找到最优解,即成本(cost)最低的解吗?
  • 时间复杂度:生成或扩展的节点数目。空间复杂度:存储的节点最多时的数量。由以下三个值衡量:b(branch,搜索树中的各个节点node的最大分支因子,即最大分支数,这里的分支指的是从节点node开始,agent可进行的行动action,也就是说节点node的分支数为:从节点node开始,agent可进行的行动action的个数);d(depth,解的深度);m(即状态空间的最大深度,可能为无穷)。

7 无信息搜索

无信息搜索指的是,搜索策略没有超出问题定义提供的状态之外的附加信息。无信息搜索(uninformed search)也称为盲目搜索。

有以下几种搜索算法:

  • 宽度优先搜索(BFS, Breadth-first search),总是扩展最浅层的节点。
  • 一致代价搜索(UCS,Uniform-cost search),总是扩展耗费(cost)最小/少的节点。
  • 深度优先搜索(DFS, Depth-first search),总是扩展最深层的节点。
  • 深度受限搜索(DLS, Depth-limited search)。有深度限制的深度优先搜索。若状态空间无限,深度优先搜索就会发生失败。这个问题可以用一个预定的深度限制l得到解决,即:深度l以外的节点被视为没有后继节点。注意:如果能够知道最优解所在的深度的话,DLS的最优解的完备性与最优性很好。除此之外,DLS的空间复杂度与时间复杂度(1)在最差的情况下,与BFS一致(2)最好的情况下会好得多。

7.1 cost一样的BFS示例

1、下图中,从节点A开始扩展,按照BFS,每次扩展都是先扩展最浅层节点,使用FIFO queue来记录Frontier集。节点中深色为当前已扩展的节点(Explored),浅色代表未扩展的节点(Frontier):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_02


2、上图可能看不清楚,那再看看这个:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_03


BFS具体过程如下,其中G为目标状态节点:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_04


3、看下图:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_05


下图为使用BFS解决上述问题的实现细节(下图的过程是不完整的),使用的是FIFO队列,是在扩展前做的goal test:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_06


注意:BFS的空间复杂度与时间复杂度较差,但是解的完备性与最优性很好。

注意:在BFS中,若新生成的节点node已经出现在Explored或Frontier集中,则丢弃此节点,进行下一步。

7.2 cost一样的DFS示例

注意:与BFS形成对比,DFS使用的是LIFO队列,即使用的是stack栈。且是在生成节点时做的goal test。

先介绍一下什么是八数码问题,在3*3的棋盘上,有1-8共8个数字,剩余一个空的格子。目标是将棋盘上的数字按下图排列:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_07


即上述状态即为目标状态Sg。仔细看看下图(S0为初始状态,各个状态已标好序号,注意使用的是栈来存储Frontier集,即LIFO,图片右下角只列出部分过程):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_08


注意:与BFS形成对比,DFS的空间复杂度与时间复杂度较好,但是最优解的完备性与最优性不是很好。

注意:7.1节与7.2节使用的BFS与DFS中,每个状态之间的转移成本cost大小是一样的。下面看看不同状态之间的转移成本cost不一样的情况。

7.3 cost不一样的BFS示例

看下图,目标是从初始状态S到目标状态G,且路径成本cost最低:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_09


过程如下:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_10


2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_人工智能_11


2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_12


2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_13


2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_14

在第7步扩展节点前做的goal test中(其实,在BFS中,每次在扩展Frontier中的头一个节点之前,都要做goal test,只不过我在前六步中没写,因为这六步做goal test都是失败,所以就没写,希望读者明白BFS必须在扩展前做goal test),发现已经找到G,停止BFS算法。此时,解的路径为S-B-G,cost为6+9=15。通过观察,路径S-C-E-F-G为最优解,cost为14<15。所以说,在不同状态之间的转移成本cost不一样的情况下,BFS算法找到的解不一定是最优解。

下图为该问题的BFS搜索树,可见问题的解(不是最优解)的深度为3:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_15


根据本博文【6 不同策略的评价指标】提到的4个标准,宽度优先搜索BFS的性能怎样呢?宽度优先搜索是完备的——如果最浅的目标结点处于一个有限深度d,宽度优先搜索在扩展完比它浅的所有结点(假设分支因子b是有限的)之后最终一定能找到该目标结点。请注意目标结点一经生成,则它一定是最浅的目标结点,原因是所有比它的浅的结点在此之前已经生成并且肯定未能通过目标测试。

但是最浅的目标结点不一定就是最优的目标结点;从技术上看,如果路径代价是基于结点深度的非递减函数,宽度优先搜索是最优的。最常见的情况就是当所有的行动要花费相同的代价

7.4 cost不一样的DFS示例

看下图,目标是从初始状态S到目标状态G,且路径成本cost最低(问题和7.3节的一样,这次是用DFS解决问题):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_09


过程如下:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_17


在第5步生成节点后做的goal test中(其实,在DFS中,每次在生成节点时,都要做goal test),发现已经找到G,停止DFS算法。此时,解的路径为S-A-D-F-G,cost为3+3+5+5=16。通过观察,路径S-C-E-F-G为最优解,cost为14<16。所以说,在不同状态之间的转移成本cost不一样的情况下,DFS算法找到的解也不一定是最优解(BFS也是这样的)。下图为该问题的DFS搜索树,可见问题的解(不是最优解)的深度为4:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_18

7.5 UCS示例

UCS中文名称为代价一致搜索或一致代价搜索。UCS总能找到最优解,因为UCS总是先扩展【从初始节点到自己cost最小】的那个节点,且算法停止条件为找到解或者Frontier集为空。因为UCS会在node的数据结构中记录从初始节点到当前节点的cost,并按照Frontier集中每个节点的cost大小,从小到大将未扩展的节点排序,即Frontier集的数据结构为优先级队列(Priority Queue)。所以和DFS与BFS不一样,不需要区分问题中不同状态之间的转移成本cost一样或者不一样。

注意:UCS在扩展节点前做goal test,因为第一次生成目标节点时的路径可能不是最优解。而且,在每次生成曾经已经出现的节点node时,先做的是比较【从初始状态到node对应的状态的旧路径的cost】与【从初始状态到node对应的状态的新路径的cost】的大小关系:若后者更小,则舍弃旧的路径,替换为新路径;若前者更小,则抛弃当前生成的节点node代表的路径,旧路径保持不变。

下面是UCS的伪代码(g(n)=从初始状态到当前节点node对应的状态的cost):

function UCS(initialState, goalTest):  # return Success or Failure, cost f(n)=g(n)
frontier = priorityQueue.new(initialState) # add initialState to frontier which is a priority queue
explored = Set.new() # explored set

while not frontier.isEmpty():
state = frontier.deleteMin() # extend the node whose cost is minimum
explored.add(state)

if goalTest(state):
return Success(state)

for neighbor in state.neighbors(): # note here are neighbors instead of successors
if neighbor not in frontier or explored:
frontier.insert(neighbor)
else if neighbor in frontier:
frontier.decreaseKey(neighbor) # compare cost between new path and old path, choose one whose cost is less and discard another one

return Failure # can't find solution

看下图,目标是从初始状态S到目标状态G,且路径成本cost最低(问题和7.3节、7.4节的一样,这次是用UCS解决问题):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_09


过程如下(表中的Priority Queue中字母为未扩展的节点,数字代表从初始节点S到当前节点的cost):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_20


注意,下面解释上图。内容很多,可能比较复杂:

(1)第3步扩展C时,可得到E3与S4,而S在第1步为S0<S4,所以抛弃S4,上图中加粗代表实际不在队列的值,下面不再重复说明;

(2)第4步扩展A时,可得到S6与D6,而S在第1步为S0<S6,所以抛弃S6;

(3)第5步扩展E时,可得到C4、B5、H8与F9,而C在第2步为C2<C4,所以抛弃C4。值得注意的是这里的B从上一步的B6变为这里的B5,B6之所以被替换为B5,是因为B5(路径为S-A-E-B,cost为5)比B6(路径为S-B,cost为6)的cost小,而且要注意替换后的B的父节点为E而不是S。也就是说在这一步,在扩展B之前又得到了一个更优的从S到B的路径;

(4)第6步扩展B时,可得到E7、D9、S11、G14,而E在第3步为E3<E7,所以抛弃E7;而D在第4步为D6<D9,所以抛弃D9;而S在第1步为S0<S11,所以抛弃S11;

(5)第7步扩展D时,可得到A9、B10与F11,而A在第2步为A3<A9,所以抛弃A9;而B在第5步为B5<B10,所以抛弃B10;而F在第5步为F9<F11,所以抛弃F11;

(6)第8步扩展H时,可得到E13、G16,而E在第3步为E3<E13,所以抛弃E13;而G在第6步为G14<G16,所以抛弃G16;

(7)第9步扩展F时,可得到D14、G14(*)与E15,而E在第3步为E3<E15,所以抛弃E15;注意G14没有变,但是必须知道的是:下图的G14的路径为S-C-E-B-G,刚刚提到的G14(*)的路径为S-C-E-F-G。本问题中UCS算法选择的是G14而不是G14(*),因为前者是先生成的;

(8)第10步扩展G前做goal test时(其实UCS在每次扩展节点前都先做goal test),可得到目标G,于是找到了解,而且Frontier此时(Priority Queue)为空,因此此时的解为最优解。结束UCS算法。找到的最优解的路径为:S-C-E-B-G,cost为2+1+2+9=14。下面加粗的线便是UCS找到的最优解的序列:S-C-E-B-G。

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_21


UCS算法在复杂问题上虽然总可以找到最优解,但是有时候走的路径比较绕远,即时间复杂度与空间复杂度上表现较差。

7.6 深度受限搜索DLS

在无限状态空间,深度优先搜索DFS会令人尴尬地失败,而这个问题可以通过对深度优先搜索设置界限L来避免。就是说,深度为L的结点被当作没有后继对待。这种方法称为深度受限搜索(depth-limited search,DLS)。

深度界限的设置解决了无穷路径的问题。不幸的是,如果选择了L<D,即是说,最浅的目标结点的深度超过了深度限制,那么这种搜索算法是不完备的;如果选择的L>D,深度受限搜索同样也不是最优的。

深度优先搜索可以看作是特殊的深度受限搜索,其深度L=oo。对于大多数问题,在找到解之前,是无法知道一个好的深度界限L的。深度受限搜索可以通过修改一般的树搜索算法或者图搜索算法来实现。

要注意的是深度受限搜索可能因为两种失败而终止:返回值指示无解;在深度界限内无解

8 有信息(启发式)搜索

无信息搜索(uninformed search)也称为盲目搜索有信息搜索(informed search)也叫启发式搜索。启发式搜索会利用问题本身定义外的特定知识。有信息指的是要考虑目标状态与每个状态的之间的关系(Relationship),即拥有每个状态与目标状态之间的某些信息,通过这个关系Relationship来协助进行搜索过程。

启发式搜索会使用域知识(domain knowledge):

1、知识1:现在是否离目标更近?

2、知识2:启发式函数(heuristic function,h(n)),h(n)=结点n到目标结点的路径的代价估计值。用来估计每个状态与目标状态的接近程度。启发式函数不总需要找最好的那一个,但是在搜索空间非常大时,任何启发式函数对问题的解决都有着巨大的作用,比如可以缩小时间或空间成本。

下面介绍两种启发式搜索方法:

  • GBF算法
  • A*算法

8.1 GBF示例

贪婪最佳优先搜索(Greedy best-first search,GBF)。GBF先扩展与目标最近的节点,因为这样可能最快找到解。因此,GBF只使用启发式信息(heuristic function,h(n),n为节点),即f(n)=h(n)。

下面是GBF的伪代码(与UCS代码基本相同,区别为f(n)由g(n)变为h(n);在扩展节点前做goal test):

function GBF(initialState, goalTest):  # return Success or Failure, cost f(n)=h(n)
frontier = priorityQueue.new(initialState) # add initialState to frontier which is a priority queue
explored = Set.new() # explored set

while not frontier.isEmpty():
state = frontier.deleteMin() # extend the node whose cost is minimum,here is minimum(h(n))
explored.add(state)

if goalTest(state):
return Success(state)

for neighbor in state.neighbors(): # note here are neighbors instead of successors
if neighbor not in frontier or explored:
frontier.insert(neighbor)
else if neighbor in frontier:
frontier.decreaseKey(neighbor) # compare cost between new path and old path, choose one whose cost is less and discard another one, ,here is also less(h(n))

return Failure # can't find solution

现在有一个实际问题,问题的目标是从“Saint louis”到达“Sault Ste Marie”。将函数设为启发式函数,即设置为节点n到目标节点的直线距离,因为沿着【到目标节点的直线距离最短】的节点node可能更快找到解。即在这里h(n)=节点n到目标节点的直线距离,所以每次扩展的是frontier集中h(n)最小,即到目标节点的直线距离最短时对应的节点node。看下图,左面为地图,有直线连接的两个城市代表之间有真实的路,反之亦然;右面为各个城市到Sault Ste Marie的直线距离(估计值),如从Atlanta到Sault Ste Marie直线距离为272,从Saint louis到Sault Ste Marie直线距离为180,从Sault Ste Marie到Sault Ste Marie直线距离为0(自己到自己当然是0)。

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_22


下面是更大些的地图,很模糊,数字可能根本看不清楚:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_23

下面是第一步(请做好准备,因为随着节点的扩展,搜索树变得越来越复杂,而且图也可能到后面就看不清楚了,抱歉):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_24


根据下图分析发现:与Saint louis有路的4个城市为K176、L240、N221、C107(字母代表城市,太长这里就用首字母了;数字代表相应城市到Sault Ste Marie的直线距离,根据上图右侧数据可以得到)。

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_最优解_25


下面是第二步:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_26


下面是第三步:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_27


下面是第四步:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_28


第五步(我没画图)在扩展前做goal test(其实GBF在每次扩展节点前都先做goal test),成功找到Sault Ste Marie,停止GBF算法。解如下:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_29

8.2 A*算法示例1

先介绍A算法:A算法也是一种启发式搜索算法,但是A算法与UCS算法(UCS为无信息搜索算法,不是启发式搜索算法)都没有对估价函数f(n)做任何限制。而估价函数对搜索过程是十分重要的,如果选择不当,则有可能找不到问题的解或者找到的不是问题的最优解。为此,需要对估价函数进行某些限制。A*算法就是对A算法的估价函数f(n)=g(n)+h(n加上一些限制后,得到的一种启发式搜索算法。

假设f*(n)为从初始节点S0出发,经过节点n到达目标节点的最小代价值。估价函数f(n)则是f*(n)的估计值。显然,f*(n)应由两部分所组成:(1)从初始节点S0到节点n的最小代价,记为g*(n);(2)从节点n到目标节点的最小代价,记为h*(n)。当Frontier集中有多个节点未扩展时,应选取其中代价最小的一个节点。因此有f*(n)=g*(n)+h*(n)。把估价函数f(n)与f*(n)相比,g(n)是对g*(n)的一个估计,h(n)是对h*(n)的一个估计。尽管g(n)的值容易计算,但它不一定就是从初始节点S0到节点n的真正最小代价,很有可能从初始节点S0到节点n的真正最小代价还没有找到。

如果对A算法中的g(n)和h(n)分别提出如下两个限制:

(1)g(n)是对g*(n)的估计,且g(n)>0;

(2)h(n)是h*(n)的下界,即对任意节点n均有h*(n)>=h(n);

则称得到的A算法称为A*算法。

当解决问题的最佳路径存在时,若某一搜索算法一定能找到它,则称此算法是可纳的。A*算法是可纳算法。A*算法是全局择优的启发式搜索,而且一定能找到全局最优解。

下面是A*的伪代码(与UCS和GBF代码基本相同,区别为f(n)=g(n)+h(n);在扩展节点前做goal test):

function A_star(initialState, goalTest):  # return Success or Failure, cost f(n)=g(n)+h(n)
frontier = priorityQueue.new(initialState) # add initialState to frontier which is a priority queue
explored = Set.new() # explored set

while not frontier.isEmpty():
state = frontier.deleteMin() # extend the node whose cost is minimum,here is minimum(f(n))
explored.add(state)

if goalTest(state):
return Success(state)

for neighbor in state.neighbors(): # note here are neighbors instead of successors
if neighbor not in frontier or explored:
frontier.insert(neighbor)
else if neighbor in frontier:
frontier.decreaseKey(neighbor) # compare cost between new path and old path, choose one whose cost is less and discard another one

return Failure # can't find solution

与上面8.1节的问题一样,目标还是从“Saint louis”到达“Sault Ste Marie”,现在用A*算法解决这个问题。在这里h(n)=节点n到目标节点的直线距离(估计值);g(n)=初始节点到结点n的路径长度(实际代价)。f(n)=g(n)+h(n)。如下:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_30


下面是更大些的地图,很模糊,数字可能根本看不清楚:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_23


下面是第一步(注意f(Louis)=g(Louis)+h(Louis)=0+180=180):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_人工智能_32


下面是第二步(请做好准备,因为随着节点的扩展,搜索树变得越来越复杂,而且图也可能到后面就看不清楚了,抱歉):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_33


下面是第三步:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_34


下面是第四步:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_人工智能_35


下面是第五步(下图中所有f(n)都应该是h(n),打错了,注意):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_人工智能_36


下面是第六步(下图中所有f(n)都应该是h(n),打错了,注意):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_37


下面是第七步(下图中所有f(n)都应该是h(n),打错了,注意):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索算法_38


下面是第八步(下图中所有f(n)都应该是h(n),打错了,注意):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_人工智能_39


下面是第九步(下图中所有f(n)都应该是h(n),打错了,注意):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_40


在第九步扩展节点前做goal test(其实A*在每次扩展节点前都先做goal test),成功找到Sault Ste Marie,停止A*算法。解序列为:S-C-P-T-Sault Ste Marie,这里我用了首字母,就是上图(第九步的图)从Saint louis开始,沿最左侧节点到Sault Ste Marie。

8.3 A*算法示例2

问题是八数码问题:在3*3的棋盘上,有1-8共8个数字,剩余一个空的格子。目标是将棋盘上的数字按下图排列:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_07


即上述状态即为目标状态Sg。下图为初始状态initial state。规定A*算法的h(n)为节点node对应的棋盘状态中,与目标棋盘相比,【不在位的数移到应该在的位置所需的步数总和】(如初始状态的h(n)为4,因为1、2、8不在位,把1、2、8移到对应位置所需步数分别为1、1、2,总和为4);g(n)为深度,即实际对空格的移动次数(如初始状态的g(n)为0,因为空格还未移动):

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_AI_42


下图为搜索树及A*算法解决该问题的完整过程:

2 通过“搜索”求问题的解(9.28,10.5,10.12,10.19)_搜索_43


问题的解已经画在图片上了。如果你想获得上图的PDF格式版本,请​​点击这里​​。

END


举报

相关推荐

0 条评论