searching (informed and non-informed)

搜索基础:
搜索算法需要构造搜索树,树中的每个节点应该包括以下元素:
1. 对应状态空间中的状态
2. 父节点
3. 父节点产生该节点时产生的行动

4. 代价,初始状态到该节点的路径消耗

树搜索和图搜索,树搜索会存在环路的问题,因为搜索A->B,后又搜索了B->A。图搜索添加了一个搜索属性搜索集,所有被搜索过的节点不会再被搜索,解决了环路问题。深度优先用树搜索会出问题,解决方法是用深度限制搜索,以下会详述。

无信息搜索策略:
1. 宽度优先搜索:用先进先出的队列模拟搜索树,迭代搜索,宽度优先搜索出来的一定是最优解,因为不可能存在更短的路径已经全都搜索过了。
时间复杂度: O(b^d)
空间复杂度:O(b^d)

b为分叉,d为最优解深度,由上面可知时间和空间复杂度都是很高

//queue中原来只有根节点
//搜索集原来为空
BFS(){
			while(queue != NULL){
				node = pop(queue);
				把node添加进入搜索集中
				if (node不是所求解){
					for(node的所有子节点){
						if(该节点不在搜索集中)	insert(queue);
					}
				}
			}
		}



2. 一致代价搜索:用优先级队列模拟搜索树,当考虑扩展子节点的代价问题时,采用此法而不用宽搜可以保证最优解,每次扩展路径代价最小的节点,例如从根节点到A,B,C的代价分别为3,5,7,则首先扩展A,产生D,E,从根节点经A到D,E分别为1,2,在B,C,D,E,中首先扩展D。以此类推。实际操作时,每个入队的节点的优先级是根节点到达它的代价。宽度优先搜索是一直代价搜索在代价都相同的情况下的一个特例。
时间和空间复杂度类似于宽搜,但是不能用b和d表示。

3. 深度优先搜索:用后进先出的队列模拟搜索树,递归搜索。最明显的缺点是搜出来的一般不是最优解,即,存在比第一个搜出来的解代价更小的解。
时间复杂度: O(b^m),稍逊于BFS,因为这个复杂度一定会大于BFS的复杂度,但是具体大多少取决于m有多大,d有多小。
空间复杂度: O(bm)其中m是搜索树的最深深度,一般来说这个值都会比O(b^d)小很多,除非m很大d很小。
//queue中原来只有根节点
//搜索集原来为空

		DFS(){
			node = pop(queue);
				  把node添加进入搜索集中
			if(node 不是所求解){
				for (node的所有子节点){
					if(该节点不在搜索集中) {
						insert(queue);//扩展子节点添加进队列
						DFS();//继续搜子节点
					}
				}
			}
			else{
				打印
			}
		}




4. 深度受限搜索:给深度优先搜索树设置一个深度,可以排除深度无限的树无法搜索的情况,例如,罗马尼亚的20个城市问题。如果深搜的不好可能会进入死循环(A->B, B->A, A->B。。。)
如果设置一个限制深度,例如19,则可以排除这个问题。


5. 迭代加深搜索:基于深度受限搜索,每次搜索深度增加1,能搜到最优解。且复杂度结合了深搜和宽搜的优点,是很好的搜索方法
时间复杂度: O(b^d)
空间复杂度: O(bd)

6.双向搜索
双向搜索比单向搜索优的直接原因是O(b^d)要大于2*O(b^(d/2))。
但是,某些问题无法使用双向搜索。例如,目标状态不明确的问题(八皇后)。而有些问题用双向搜索则会快很多,例如八数码问题和罗马尼亚问题。
双向搜索的目标检测是判断两个方向的搜索的边缘节点集是否有交集,若有的话则找到了一个解。缺点是即便两边都用宽搜也不能保证找到的解是最优解。
时间复杂度:O(b^(d/2))

空间复杂度: O(b^(d/2))


有信息(启发式)搜索策略
1. 贪婪最佳优先搜索
启发式的搜索策略是一种基于启发函数的深度优先搜索,启发函数h(n)是对节点n到目标状态的代价评估函数。
举例来说,在求最短路的问题中,A地到目的地的直线距离就可以作为h(A)的值。贪婪最佳优先搜索算法在扩展节点时采用的策略是先扩展代价低的子节点,例如根节点有A,B,C三个子节点,其中A到目的地的代价最小,那么我们首先扩展A。再从A开始根据A的子节点的启发函数的值继续扩展。
该算法存在两个致命的问题
1. 搜索的结果不一定是最优的
每一步都贪心不能保证整体的最优
2. 树搜索不完备(图搜索是完备的)
如果采用树搜索可能存在一种情况:A地的子节点中B的启发函数值最小,B地的子节点中A的启发函数值最小,这样就会陷入A,B之间不停往返的死循环。

2. A*搜索
算法步骤:
定义:
开放列表
封闭列表
g(n):到达n节点所花费的代价
h(n):节点n到目的地的估计代价
f(n):经过n节点的最小代价解的估计代价
1. 将开始节点放入开放列表(开始节点的g值视为0); 
2. 重复一下步骤:  
i. 在开放列表中查找具有最小f值的节点,并把查找到的节点作为当前节点; 
ii. 把当前节点从开放列表删除, 加入到封闭列表; 
iii. 对当前节点相邻的每一个节点依次执行以下步骤:  
1. 如果该相邻节点不可通行或者该相邻节点已经在封闭列表中,则什么操作也不执行,继续检验下一个节点;  
2. 如果该相邻节点不在开放列表中,则将该节点添加到开放列表中, 并将该相邻节点的父节点设为当前节点,同时计算并保存该相邻节点的g,h,和f值;  
3. 如果该相邻节点在开放列表中, 则判断经由当前节点到达该相邻节点的g值是否小于原来保存的g值,若小于,则将该相邻节点的父节点设为当前节点,并重新设置该相邻节点的g和f值. 
iv. 循环结束条件: 当终点节点被加入到开放列表作为待检验节点时, 表示路径被找到,此时应终止循环;  或者当开放列表为空,表明已无可以添加的新节点,而已检验的节点中没有终点节点则意味着路径无法被找到,此时也结束循环;  
3. 从终点节点开始沿父节点遍历, 并保存整个遍历到的节点坐标,遍历所得的节点就是最后得到的路径;

保证最优性的条件
1. 可采纳性
h(n)不会过高的估计从节点n到目的地的代价,即h(n)<=h^*(n)其中h^*(n)为从节点n到目的地的实际代价
2. 一致性
从节点n到目的地的估计代价必须小于从节点n到节点n'的代价加上从n'到目的地的估计代价,即h(n)<=h(n')+cost(n,n'),这实际上是保证了三角不等式
一致都是可采纳的,但是可采纳不一定是一致的,要找出这个例子有难度,所以我们这里先假设我们讨论的h(n)都是一致的。

A*算法的最优性证明
可以证明,如果h(n)是可采纳的,那么它的树搜索版本是最优的,如果h(n)是一致的,那么它的图搜索版本是最优的
我们先证明,如果h(n)是一致的,则沿着任何路径的f(n)都是非递减的。
假设在一条路径上,n'是n的后继,我们有
g(n') = cost(n,n') + g(n)
f(n') = g(n')+h(n') = g(n) + cost(n,n') + h(n') >= g(n) + h(n) = f(n)
既然f(n)是非递减的,按照A*算法,我们每次选择开启列表中的f(n)最小的点,这样可以保证n点第一次被选择时的f(n)一定小于它以后被选择时的f(n),原因很简单,当你第一次选择n点时开启列表中其它所有点的f值都大于f(n),假如存在一条更短的路到达n点,那么它必然经过开启列表中的其它点,但是由于f函数是递增的,其它点目前的f值已经大于f(n)了,经由它们的路径长度肯定比f(n)更大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值