1. 对于BFS,即广度优先搜索,要用到队列,每次从队首取元素,每次将队首的直接指向的结点放入队尾,直到搜索到最后的结果,与层序遍历完全一致。
下面的题目,给出一个n*m的迷宫,起始结点S,终止结点T,判断是否能从S到达T,并输出路径长度。
按照BFS的思想,将S压入队列,每次从队首取出一个结点,将从该结点出发的四个方向上未被访问过的结点压入队列,直到到达终止结点,并用一个结构体记录从S到达该结点的路径长度:
代码为:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 100
struct node{
int x;
int y;
int step;//从其实点到该点的最小步数,即层数
}S, T, Node;
char maze[maxn][maxn];
bool inq[maxn][maxn] = {false};//(x, y)是否已经入队过
int X[4] = {0, 0, 1, -1};
int Y[4] = {1, -1, 0, 0};
int n, m; //表示n*m的迷宫
bool test(int x, int y)//测试坐标是否是有效的
{
if(x >= n || x < 0 || y >= m || y < 0)//下标从0开始
return false;
if(maze[x][y] == '*')
return false;
if(inq[x][y] == true)
return false;
return true;//输入可以是S,T字符的形式
}
int BFS()
{
queue<node> Q;
Q.push(S);
while(!Q.empty())
{
node top = Q.front();
Q.pop();
if(top.x == T.x && top.y == T.y)
return top.step;//能到达终点的情况
for(int i = 0; i < 4; i++)//遍历四个方向
{
int newX = top.x + X[i];
int newY = top.y + Y[i];
if(test(newX, newY))
{
Node.x = newX;
Node.y = newY;
Node.step = top.step + 1;
Q.push(Node);
inq[newX][newY] = true;
}
}
}
return -1;//无法到达终点时,返回-1
}
int main()
{
scanf("%d%d", &n, &m);
//scanf()不会读入空格或者换行符,结束输入时,缓冲区还有换行符
//而gets()则会读入空格或换行符,并将换行符转换为0,缓冲区不会剩下换行符
//所以先scanf又换行后,用到gets()时,直接用,只会读一个换行符并转换为0,加上一个getchar()接收换行符,才能读到真正的字符串
//而scanf()换行后又用到scanf,可以理解为scanf会从第一个不是空格或换行符开始一直读到空格或者换行符为止
for(int i = 0; i < n; i++)
{
scanf("%s", maze[i]);
}
scanf("%d%d%d%d", &S.x, &S.y, &T.x, &T.y);
S.step = 0;
printf("%d\n", BFS());
return 0;
}
运行结果:
还是比较简单的。
2.DFS解法:
DFS与先序遍历思想是一样的,从一个结点的分支一直往下,如果没有找到目标,返回上一个分支,寻找其他未遍历的分支进行,直到找到目标,不借助数据结构,通过递归的思想找到目标。
思路是在每一个进行四个方向的探索时,进行DFS递归:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 100
struct node{
int x;
int y;
int step;//从其实点到该点的最小步数,即层数
}S, T, Node;
char maze[maxn][maxn];
bool visit[maxn][maxn] = {false};//(x, y)是否已经入队过
int X[4] = {0, 0, 1, -1};
int Y[4] = {1, -1, 0, 0};
int n, m; //表示n*m的迷宫
bool test(int x, int y)//测试坐标是否是有效的
{
if(x >= n || x < 0 || y >= m || y < 0)//下标从0开始
return false;
if(maze[x][y] == '*')
return false;
if(visit[x][y] == true)
return false;
return true;//输入可以是S,T字符的形式
}
int DFS(int x1, int y1, int depth)
{
int d = depth;
visit[x1][y1] = true;
if(x1 == T.x && y1 == T.y)
return d;
for(int i = 0; i < 4; i++)
{
int newX = x1 + X[i];
int newY = y1 + Y[i];
if(test(newX, newY))
{
d = DFS(newX, newY, depth + 1);
if(d != -1)
return d;
}
}
return -1;//不能到达终止结点时返回-1
}
int main()
{
scanf("%d%d", &n, &m);
//scanf()不会读入空格或者换行符,结束输入时,缓冲区还有换行符
//而gets()则会读入空格或换行符,并将换行符转换为0,缓冲区不会剩下换行符
//所以先scanf又换行后,用到gets()时,直接用,只会读一个换行符并转换为0,加上一个getchar()接收换行符,才能读到真正的字符串
//而scanf()换行后又用到scanf,可以理解为scanf会从第一个不是空格或换行符开始一直读到空格或者换行符为止
for(int i = 0; i < n; i++)
{
scanf("%s", maze[i]);
}
scanf("%d%d%d%d", &S.x, &S.y, &T.x, &T.y);
S.step = 0;
printf("%d\n", DFS(S.x, S.y, 0));
return 0;
}
运行结果: