BFS与DFS解决迷宫问题

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;
}

 运行结果:

 

发布了112 篇原创文章 · 获赞 30 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览