搜索分为DFS 深度优先搜索 和 BFS 广度优先搜索。搜索的大致结构都为一棵树的形状。
1. 首先我们先来说一下DFS,DFS为深度优先搜索,他的最大特点就是深度优先,以深度为准则,一路走下去,直到达到目标。如果没有达到目标而且又无路可走, 就会返回上一步(这就是所说的回溯)。从他使用的数据结构来看,他所用的是栈, 先进后出。
我以一道排列数字的题目为例子进行讲解。
这里以n = 3 为例子进行解释。首先第一个位置可以先把数字1填上去1_ _,
然后接着进行下一步,数字1已经填写过那么下一步可以把2填写上去,现在的结果是1 2 _ ;
接着再往下继续走,1,2都已经填写过了,只剩下数字3,所以他的结果只能是1 2 3;
此时,3位数字已经全部填写完成,这一种方案已经实现,那么它就可以返回上一步再次进行下一种方案。此时数字排列情况为1 2 _,只剩下3可以进行填写zong jie,但是由于1 2 3这种排列方式已经有了,所以说不符合要求,继续返回上一步,这种状态下的排列情况是1 _ _, 2已经填写过了,所以可以把数字3填写上去,排列情况是1 3 _,;
再往下继续排列,是剩下数字3,此时再次完成一种排列方式1 3 2;
3 个数字再次填写完成之后,再次返回上一步,1 3_, 数字2 已经写过,所以继续返回上一步 1 _ _, 第二个位置可以选择的数字只有2 ,3,这两个数字都已经填写完毕,再次返回上一步_ _ _,
首位是1的方案已经全部找到,接下来可以接着从 2 开始,方法与上述相同。
把我所写代码贴在这里,供大家参考:
#include<iostream>
using namespace std;
const int N = 10;
int path[N];//保存序列
int state[N];//数字是否被用过
int n;
void dfs(int u)
{
if(u > n)//数字填完了,输出
{
for(int i = 1; i <= n; i++)//输出方案
cout << path[i] << " ";
cout << endl;
}
for(int i = 1; i <= n; i++)//空位上可以选择的数字为:1 - n
{
if(!state[i])//如果数字 i 没有被用过
{
path[u] = i;//放入空位
state[i] = 1;//数字被用,修改状态
dfs(u + 1);//填下一个位
state[i] = 0;//回溯,取出 i
}
}
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
2. 接着来说一下 BFS ,BFS与DFS不同的是,DFS在搜索过程中不管有多少岔路口都是一路走下去,直到找到目标或者是无路可走再返回上一个路口,而 BFS 则是在面对岔路口时,先把所有的岔路口都记录下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路,并重复这样的操作。从他使用的数据结构来看, 他所用的数据结构是队列 (queue), 先进先出。
我依然以一道走迷宫的题为例子进行讲解:
从最开始(1,1)位置开始,查看上下左右四个方向是否有路可走,如果可以,则标记为1,以上图为例,标记为1的只有一种情况,那么就接着往下走,走到 1 的位置上时,继续查看上下左右是否有路可走,如果可以则标记为 2, 此时只有一条路,那么就沿着这条路往下走走到 2 的位置,在 2 的位置查看,发现有向下和向右两条路可以走,那就把这两条路全部标记为 3 ,任意选择一条路走下去,把它能走的路标记完之后,再次走到另外一个 3 的路上把它能走的路也全部标记,接着任选一条标记为 3 的路接着走下去,后面就像上述所,描述的一样,直到走到终点。此时走到终点的路就是最短路。
把我所写代码粘贴上去供大家参考:
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 110;
int g[N][N];//存储地图
int f[N][N];//存储距离
int n, m;
void bfs(int a, int b)//广度优先遍历
{
queue<PII> q;
q.push({a, b});//存下初始点位置
f[0][0] = 0;
while(!q.empty())
{
PII start = q.front();
q.pop();
g[start.first][start.second] = 1;
int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};
for(int i = 0; i < 4; i++)//往四个方向走
{
int x = start.first + dx[i], y = start.second + dy[i];//当前点能走到的点
if(g[x][y] == 0) //如果还没有走过
{
g[x][y] = 1;//走到这个点,并计算距离
f[x][y] = f[start.first][start.second] + 1;//从当前点走过去,则距离等于当前点的距离+1.
q.push({x, y});//这个点放入队列,用来走到和它相邻的点。
}
}
}
cout << f[n][m];
}
int main()
{
memset(g, 1, sizeof(g));
cin >> n >>m;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin >> g[i][j];
}
}
bfs(1,1);
return 0;
}