dls 深度受限搜索java_经典搜索算法总结

本文内容主要来自Artificial Intelligence A Modern Approach和Stanford CS221。

人工智能可以被建模成:学习,模型,推断。所谓的搜索往往指的是根据模型推断的过程。

本文的内容主要包括

  • 搜索算法的背景和定义
  • 无信息搜索算法
    • 宽度优先搜索BFS
    • 统一代价搜索UCS
    • 深度优先搜索DFS
    • 深度受限搜索DLS
    • 迭代加深搜索IDS
    • 双向搜索BS
  • 有信息搜索算法
    • 贪心搜索
    • A* 搜索
    • 迭代最佳优先搜索RBFS
  • 启发式设计

搜索算法的背景和定义

首先,搜索算法可以分为树搜索图搜索

简单来说,树搜索算法可能会导致状态的重复,所以在图上往往使用图搜索,当然如果你可以保证你的算法不会遇到重复状态的话,也可以放心的使用树搜索。

树搜索:

d44f5be1bcfe7a5bb3a181384482c7e7.png

图搜索:

423551f2fd9bc301ea840c5e22f4eb99.png

容易看出,图搜索比树搜索多维护了一个explored队列,这个队列用来记录算法经过的节点,通过检查新的节点是否在这个队列中,图搜索避免了重复。

而两者都有的frontier队列,则是用来记录将要探索的节点。

算法开始的时候把初始节点放到 frontier里,接下来一直探索,如果frontier空了却没有找到最终的目标,说明目标是不存在的,算法返回failure。

其次是对节点的描述,一个节点包括:

711a6016e5ba8b7a8a0833a37968e233.png

其中关于STATE,CS221给出了一个很好的解释:

A state is a summary of all the past actions sufficient to choose future actions optimally.

最后是描述算法好坏的指标:

  • Completeness: Is the algorithm guaranteed to find a solution when there is one?
  • Optimality: Does the strategy find the optimal solution?
  • Time complexity: How long does it take to find a solution?
  • Space complexity: How much memory is needed to perform the search?

为了描述后两个性能指标,我们在图搜索上定义一些常数(这些常数由问题确定,与算法无关)

  • branching factor b:一个节点的最多分支
  • maximum depth m:整个图的最大深度
  • solution depth d:最优解所在的深度

无信息搜索算法

宽度优先搜索BFS

0f20f405d57458353409cb3f8a8e7d11.png

说白了BFS就是用一个FIFO的队列维护frontier中的节点。

我们用BFS的目标是找到目标节点,但是这个从初始节点通向目标节点的路径可能有很多条。

很多时候,我们不仅希望找到节点,还希望在搜索的过程中最小化某种指标,这个指标可以用

描述。

如果满足对任意

三元组满足
,可以证明BFS是可以找到
最优解的。

这个证明是很直观的,只需要一层层的向下找就可以了。往往这样假设的

会是时间,人数等最小单位。

注意,如果

,BFS不保证找到最优解。

因为目标节点在d层,所以BFS的时间复杂度和空间复杂度都是


统一代价搜索UCS

接下来,UCS就是来解决

的问题的。

实际上UCS也不复杂,学过了Dijkstra算法就能发现,UCS其实就是Dijkstra算法。

acb6ff0472560c7f705f56ee2b524f28.png

UCS和BFS的主要区别是UCS维护了一个优先队列,通过这个优先队列保证达到目标节点的时候路径一定是最短的。

这个也好理解,因为从frontier取出的节点满足chooses the lowest-cost node in frontier,所以如果这个节点是目标节点,那么即便是存在另一个路径也可以通向目标节点,因为当前走过的路径已经比这条路长了,又有

,所以
另一条路径不可能更短

实际上,一个更直观的事实是,任何被放入explored的节点都满足最短路径


深度优先搜索DFS

DFS和BFS的区别就是DFS用一个LIFO的队列(其实就是栈)来维护frontier

注意,因为DFS一旦找到了目标节点就会停止,所以当

无法找到最优解

但是,如果

,任意到达目标节点的解都是最优解,DFS就可以找到最优解。

这种情况往往出现在对代价几乎没有要求的情况下,例如不计时间的拼魔方。

17217f6fa127308b905e4b609df0c73e.png

值得一提的是,在树搜索算法中,DFS非常容易陷入无穷的循环,所以DFS往往用于图搜索。

因为DFS理论上要搜完整个空间才知道是否有解,所以最大的时间复杂度是

,但是因为需要记录的节点很少(毕竟是用栈维护),时间复杂度比较低,为

深度受限搜索DLS

DLS规定了DFS的最大搜索深度,对于一个给定的常数l,DLS在到达这个深度之后就会放弃搜索,转而去探索frontier中的其他节点。

5bbc68e551407996c70d680ab278a963.png

注意DLS是一个递归算法,而之前的算法都是循环的。

函数RECURSIVE-DLS可以返回三种值,除了之前的solution和failure,还有递归算法的内部状态cutoff。

对于每一个节点,算法会递归的展开它的子节点,如果有一个节点返回solution,算法会将这个solution向上传递至跟节点。

如果其中一个节点返回cutoff,算法认为到达了受限深度,向上传递cutoff。

如果这个节点的所有子节点都不返回solution或者cutoff,也就是说所有节点都返回failure,则向上传递failure。

如果最后的跟节点的输出是failure,说明DLS的受限不起作用,也就是说这个图最深的深度也没有受限的深度深

如果最后的跟节点的输出是cutoff,则说明虽然当前深度内并没有找到目标节点,但是不保证更深的节点中没有目标节点。

DLS和DFS的复杂度很像,时间和空间复杂度分别是


迭代加深搜索IDS

IDS 就是在DLS的基础上,不断的将常数l扩大,从而增加搜索深度。

e9d05757ab8752ac8beda8f1c27a3fee.png

cb98cc310bd5dfdefed983d8d9d24e82.png

IDS弥补了深度受限搜索的缺点,它允许算法不断的增加深度来寻找目标节点。

它和BFS看起来很像,而且IDS似乎在实现上产生了很大的重复,实际上IDS比BFS的空间复杂度小的多,但是时间复杂度相对大一些。

IDS的时间和空间复杂度分别是

,注意
的时间复杂度是相当高的。

双向搜索BS

BS的假设是我们不仅可以从初始节点出发,同时还可以从目标节点出发,从而实现双向的搜索。

BS的内部往往是由BFS实现的,如果从初始节点和从目标节点的搜索都是BFS,可以保证算法的最优。

实际上,BS就是将BFS画的半径为d的一个大圆,换成了半径为d/2的两个小圆

60bb9c61cdaf3e0dafff96f7ff21744c.png

因为BS是基于BFS实现的,所以时间复杂度和空间复杂度都很像,都是


最后比较一些这些算法

0c277f6dd3030c5934993b931ae8a5af.png

注意,这里DFS不完备是因为可能陷入无穷循环,不满足最优性是因为默认


有信息搜索算法

所谓的有信息搜索算法又称启发式搜索,往往假定了我们对搜索问题还有额外的知识。

启发式搜索根据evaluation function

探索,它给定了我们探索这个节点的意向。我们会优先探索
小的节点,这个探索的算法和UCS非常像。区别在于UCS是根据
已经探索过的路径信息给出接下来探索的意向。而启发式搜索则根据额外的信息。

我们可以定义

为之前探索过的节点的代价总和,那么UCS就相当于

同时,我们有一个函数heuristic function

表示

h(n) = estimated cost of the cheapest path from the state at node n to a goal state.

我们认为对于所有的

满足
,且对于目标节点满足

贪心搜索Greedy best-first search

我们假定在下面的地图上搜索,初始节点是Arad,目标节点是Bucharest。

a10f081a2af48e94720b29495f2f3146.png

贪心搜索即令

,即只根据启发进行搜索。

我们假设

是从当前城市到Bucharest的
直线距离。(注意,这个直线距离是原问题所不具备的,因此是“额外的知识”)。各个城市的
为:

d369c47c1709bbdaaf5fb9ac369f3e54.png

那么搜索的过程就是

00dcd0a5e72b007f87fd89aa622f6528.png

注意,贪心搜索不能保证最优,甚至都不能保证完备,因为它可能陷入“死胡同”,例如从Iasi到Fagaras,它会选择去Neamt,然后就卡死了。


A* 搜索

A* search的evaluation function

满足

同时,当

满足Admissibility和consistency这两种性质,A*算法可以保证找到最优解。

admissible heuristic指的是

An admissible heuristic is one that never overestimates the cost to reach the goal.

显然,在我们的例子中,因为两点之间直线最短,所以admissible是满足的。

consistent heuristic是指

for every node
and every successor
of
generated by any action a, the estimated cost of reaching the goal from
is no greater than the step cost of getting to
plus the estimated cost of reaching the goal from

也就是满足

其实,算上之前要求的对于目标节点满足

,我们对
有三个条件,分别是

而在CS221中只给了第1个和第3个条件,实际上,我们可以从1,3条件推出2,也可以从2,3条件推出1。

如果有

,对于
的前继必满足
,数学归纳得到所有的节点都满足。

如果有2,3条件,显然有

接下来,只要把UCS的

换成
就可以使用A*算法了。

6cc9385537b689a4eab7f556dcbc16e7.png

接下里,更重要的是,我们要证明A*算法的最优性。

首先不难看出

是不降的:

根据和UCS类似的推导,我们可以说明一旦任意节点

被放入
explored,它的路径都满足
最小。

这看似没什么用,因为

是我们自己定义的,对于
除了目标节点以外的节点,满足
最小
并不能保证找到了最短路径

但是目标节点不同,因为

,所以
,所以目标节点满足
最小,因此我们可以找到通往目标节点的最短路径。

A*算法满足了最优性,这个性质UCS也可以满足,那么我们为什么不用UCS而是用A*呢?

直观的理解,UCS是像圆一样从一个点蔓延,直到找到了目标节点;而A*则是朝着目标节点的方向蔓延,尽管做不到只走一条路径,但也高效的多。

我们可以用等高线的方式更好的理解这个性质:

310ca603bea2a1680a4108a140f91a1b.png

图中的等高线是

的值,我们设最优路径的代价是C*的话,因为A*和UCS的内核是一样的,它会优先探索所有
最小的节点,所以图中所有小于C*的节点都已经被探索了。

进一步讲,我们知道

  • A expands all nodes with f(n) < C*
  • A* might then expand some of the nodes right on the “goal contour” (where f(n) = C*) before selecting a goal node.

从上面的树状图可以看出,这个问题的C*是418,而

小于的节点(图中最大的虚线圈内的节点)都已经被探索了。

所以A*的一个问题就是要探索完所有

小于C*的节点,这些节点的数目可能是
指数级的

但无论如何,A*都要比UCS好,因为UCS要探索完所有

小于C*的节点,
的等高线将是
,而不是 椭圆,这意味这UCS要探索更多。

迭代最佳优先搜索RBFS

c1564373a24dd11776e73706c3221f7e.png

(算法中有一些max和min,在我看来似乎没有必要)

RBFS看起来很有意思,因为它既是一个递归算法,又在递归的内部进行了循环。

它维护了一个successor队列, 根据这个successor队列计算出了两个值,分别是bestalternativebestsuccessor最小

对应的节点,
alternativesuccessor第二小
对应的节点。

然后,算法选择扩展最小的

的节点,也就是
best对应的节点。同时把 alternative作为f-limit输入到新的子递归算法中。如果子递归发现所有 successor中的节点的
大于 f-limit,就会“放弃”现在的节点,退出这个子递归。

同时它会将这个节点(之前best的节点)的

更改为子递归传回来的值(看下图中画叉的地方)。进行下一轮扩展。

在之前的例子中,RBFS的探索过程如下:

a48e1d1720a2bddb6911840a33cbb623.png

RBFS相比A*节省了大量的空间,实际上,它的空间复杂度和节点的数目是线性的。但是因为它会在递归的过程中“遗忘”因此时间复杂度更高。


启发式设计

通过刚才A*和RBFS的例子可以看出来,一个好的

对启发式搜索起到了很大的帮助。总的来说,它可以让
小于C*的节点的数目变少,也就是让A*的等高线
更窄,让这个椭圆更扁一些,一个极端的情况是这个椭圆 只包括从初始状态到目标状态最优路径上的节点

那么,如何设计更好的

呢?

一个经典的例子是8-puzzle

99c304b4d4f88f9511c3b12164036415.png

目标是从Start State挪到Goal State。

在8-puzzle中,我们可以看到搜索树的宽度最小为2(空格在四角),最大为4(空格在中间),总的来说平均为3。

8-puzzle问题的平均移动次数是22次,需要探索

个状态。然而,通过合理的剪枝(停止探索重复状态),这个数目可以减少至181440。

但是,即便剪枝,15-puzzle对应的数目依旧达到了

,我们不得不寻找
有效的启发式

有两种启发式值得参考:

19fdf6a6000519180f98bac088d37b77.png

显然,对于所有的

,都应该满足

我们定义一个用来评价heuristic好坏的指标effective branching factor b*,它的定义为

其中

是A*算法搜索的
深度
是算法探索的
节点数

其实,直觉上,我们可以用

表示heuristic的好坏,因为
就是(近似)小于C*的节点的个数,也就是椭圆里节点的个数。

但是因为初始节点和目标节点的不同,椭圆的大小是不好确定的,这时候只统计

就没有意义了,所以我们用深度
来计算相对的branching factor。

b893ecb5828529a2c23c3d08bd66c8f5.png

可以看到

是优于
的。

这里有一个更一般的结论,因为

恒成立,所以
作为heuristic比
更好。

生成heuristic主要有三个方法,分别是

  • Generating admissible heuristics from relaxed problems
  • Generating admissible heuristics from subproblems: Pattern databases
  • Learning heuristics from experience

注意第三个会用到一些机器学习的方法,但是并不能保证heuristic是admissible和consistent的。

此外,如果我们有多个heuristic都满足admissible和consistent,我们可以得到新的heuristic

可以证明,这个新的heuristic性能更好,且满足admissible和consistent。

  • 性能好:因为
  • admissible: 每个都满足
    自然满足
  • consistent:即证
    ,其中
    ,若
    结论是显然的;若
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值