搜索算法基础

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

搜索基础

By wujiawei@hit

写的不好,大家不要笑我。。。

一、什么是搜索算法?

搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。

相比于单纯的枚举算法有了一定的方向性和目标性。我理解的搜索算法是在解的空间里,从一个状态转移(按照要求拓展)到其他状态,这样进行下去,将解的空间中的状态遍历,找到答案(目标的状态)。

二、关于状态与转移

搜索的状态是指在某一时刻的进展情况的数学表示,每一个状态都会是答案的一个“可能的”解。状态的转移就是问题从一个状态转移到另一个状态,这样就可以进行搜索的一步步延伸,最后要得到的解也是其中的一个状态。

例如:迷宫类的搜索,寻找出路,每一个位置都是一个搜索的状态,

如图,就可以表示一个迷宫的图,‘O’代表可以走的,‘X’代表陷阱,如果对这个图进行搜索的话,状态可用一对坐标(struct 或class)来表示,并且判断该状态是否可行(即要看是否是‘X’,如果是的话就不合法)。

状态的转移:初始状态为红色的,转移后的是蓝色的,这样就是一个状态的传递(如果要求是只能在横向和纵向拓展),从一个状态找到后面的状态,并一直找到答案。

目标状态:即搜索的结果,满足条件的最终状态。例如8数码中的一个摆放情况,或是迷宫的出口,终点。

三、关于状态的表示

对于一个迷宫来说状态可以用两个坐标,即根据图来确定矩阵的内容,然后以矩阵的两个下标作为状态的表式。

对于像8数码类的搜索,既可以用字符串或者是数组来表示位置间的关系:

状态可表示为 3 6 0 5 2 4 1 7 8 可用数组来存,0 表示有空缺的位置。而对应的最后搜索到的答案也是

对于图搜索,状态一般多为图上的顶点。

还有一些比较麻烦的状态,例如在迷宫中拿到钥匙和没有钥匙等。

四、广度优先搜索(BFS)

1.基本思想:从初始状态S开始,利用规则,生成所有可能的状态。构成树的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。

在路径的寻找问题上用得比较多

2.具体过程

这就是BFS的一个过程,每个方块表示一个状态,蓝色的表示遍历了该状态。广度优先即是要按层数一层一层来遍历,先将一层全部扩展,然后再进行下一层,每个可行的状态放到队列里。为什么要用队列呢?主要是由于状态是按照广度进行拓展的,层数低的先被遍历,即可以这样看,不同深度(层数)用不同的颜色来表示:

对应的队列的情况

这样利用队列先进先出(FIFO)的性质恰好可以来完成这个任务。先遇到的状态一定是比后遇到的状态深度要小。

从1节点开始,拓展出来2,3,4三个节点,此时在分别以2,3,4三个节点作为初始节点进行遍历一直到最后找到目标状态。

具体过程:

1每次取出队列首元素(初始状态),进行拓展

2然后把拓展所得到的可行状态都放到队列里面

3将初始状态删除

4一直进行以上三步直到队列为空。

While Not Queue.Empty ()

Begin

可加结束条件

Tmp = Queue.Top ()

For I = 1 To 4 Do

If Legal (Tmp.X + Dx[I], Tmp.Y + Dy[I]) Then

Begin

Next.X = tmp.X + Dx[I]

Next.Y = tmp.Y + Dy[I]

Next.Step = Tmp.Step + 1

Queue.Pushback (Next)

End

Queue.Pop ()

End

以8数码为例:

3.判重处理

在搜索的过程中有时候会遇到重复的状态,即以前已经遇到的状态,这时利用相应的方法将其删除(如果该状态是不必要的)。例如:8数码搜索到状态123456780但是该状态在以前已经搜到过,那么就不把这个状态放到队列里,否则会增加时间的开销。

再例如,一个迷宫的搜索,如果以前已经走过这个点,并且已经对其进行拓展,那么就不需再将其作为新的节点并进行拓展。

标记的时候有以下几种: Hash ,BST (set , map ),或是使用标记数组。

标记数组: a[N];

a[0 ~ N-1] = 0; // 初始时候值全为0

If ( x is legal && a[x] = = 0) // x 状态是否合法 而且 判断是否出现过

{ //如果出现过值为1 没出现过值为0

Queue.push(x);

a[x] = 1;

}

4.

以简单的迷宫搜索为例,描述一下过程

以棋盘迷宫类的问题作为出发点比较容易理解,其他类型的问题有些可以类似的思考,希望大家多看一下。

5.关于Queue

可以用数组模拟实现,还可以用C++中的STL

#include

struct point

{

Inr x, y;

}wujiawei, ans;

queue q_list; //定义声明,<>内是数据类型

q_list.push(wujiawei); //向队列中压入元素

q_list.pop(); //清除队列首元素

ans = q_list.front(); // 返回队列首元素的值,不删除

bool ret = q_list.empty(); //返回bool型队列是否为空

int n = q_list.size(); //返回队列的大小

6.推荐题目

HOJ 1797 ,1440,1422,1448,2643,2159,2298,2706

五、深度优先搜索(DFS)

1.基本思想:从初始状态S开始,利用规则生成搜索树下一层任一个结点,检查是否出现目标状态G,若未出现,以此状态利用规则生成再下一层任一个结点,再检查是否为目标节点G,若未出现,继续以上操作过程,一直进行到叶节点(即不能再生成新状态节点),当它仍不是目标状态G时,回溯到上一层结果,取另一可能扩展搜索的分支。生成新状态节点。若仍不是目标状态,就按该分支一直扩展到叶节点,若仍不是目标,采用相同的回溯办法回退到上层节点,扩展可能的分支生成新状态,…,一直进行下去,直到找到目标状态G为止。

2.过程

蓝色代表当前探索的状态,橙色为已经搜索过的状态,白色为未搜索的状态。在过程中遇到搜索的解则退出,找到答案。以深度优先为前提进行扩展。先对一个状态出发,向下搜索直到遇到目标状态,如果到最后都没有就返回上一层,搜索父节点的其他子节点。

相关文档
最新文档