美文网首页
[图]BFS应用之迷宫问题

[图]BFS应用之迷宫问题

作者: FlyingReganMian | 来源:发表于2018-05-31 11:10 被阅读0次

一般迷宫类问题(求最短路径)均可用BFS求解

1. 网易 地牢逃脱

给定一个 n 行 m 列的地牢,其中 ‘.’ 表示可以通行的位置,’X’ 表示不可通行的障碍,牛牛从(x0,y0)(x0,y0) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一些指定的步长遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上。地牢的出口可能在任意某个可以通行的位置上。牛牛想知道最坏情况下,他需要多少步才可以离开这个地牢。

输入描述:

每个输入包含 1 个测试用例。每个测试用例的第一行包含两个整数 n 和 m(1 <= n, m <= 50),表示地牢的长和宽。接下来的 n 行,每行 m 个字符,描述地牢,地牢将至少包含两个 ‘.’。接下来的一行,包含两个整数 x0, y0,表示牛牛的出发位置(0 <= x0x0< n, 0 <= y0y0< m,左上角的坐标为 (0, 0),出发位置一定是 ‘.’)。之后的一行包含一个整数 k(0 < k<= 50)表示牛牛合法的步长数,接下来的 k 行,每行两个整数 dx, dy 表示每次可选择移动的行和列步长(-50 <= dx, dy <= 50)
输出描述:

输出一行一个数字表示最坏情况下需要多少次移动可以离开地牢,如果永远无法离开,输出 -1。以下测试用例中,牛牛可以上下左右移动,在所有可通行的位置.上,地牢出口如果被设置在右下角,牛牛想离开需要移动的次数最多,为3次。
输入例子:
3 3
...
...
...
0 1
4
1 0
0 1
-1 0
0 -1

输出例子:
3

讲解:

题意:
题目中说“最坏情况下,他需要多少步才可以离开这个地牢。” 是指, 在给定地牢的形状后,出口允许设置在任意一个“.”所在的位置,主人公在知道了出口点后,会试图以最短的路径走向出口,现在需要求,如果把出口设在了一个最难以到达的位置, 需要多少步才能到达出口点。

思路:
一般迷宫问题都可以用BFS解决,本题属于迷宫问题,首先考虑BFS.
BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
在本题中,如果地牢中所有“.”点都被访问了,说明主人公可以访问任意一个节点,也就是说无论出口放在哪里,主人公都可以出地牢。

#include<iostream>
#include<cstdlib>
#include<queue>
using namespace std;

struct Node{
    int x;
    int y;
    int step;//从出发点到该节点的步数
};

int n,m;//地牢规模
char map[50][50];//地牢
int startX,startY;//出发点
int moveNum;//主人公可以行走的方式数
int moveTypes[50][2];//行走方式
queue<Node> q_node;

int BFS()
{
    int maxSteps = 0;
    int outX = -1;
    int outY = -1;
    while (!q_node.empty())
    {
        Node node_out = q_node.front();
        q_node.pop();
        maxSteps = max(maxSteps,node_out.step);//选择按照不同行走方式中步数最大的点。
        outX = node_out.x;
        outY = node_out.y;
        for(int i = 0; i < moveNum; i++)//按照不同行走方式计算可达的点
        {
            int nextX = node_out.x + moveTypes[i][0];
            int nextY = node_out.y + moveTypes[i][1];
            
            if(nextX>=0 && nextX<n && nextY>=0 &&nextY<m && map[nextX][nextY]!='X')
            {
                Node node_in;
                node_in.x = nextX;
                node_in.y = nextY;
                map[nextX][nextY] = 'X';//每访问一个点,将这个点设置为已经访问
                node_in.step = node_out.step+1;
                q_node.push(node_in);
            }
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if(map[i][j] == '.')//如果地牢中还存在“.”表明:如果出口选在该点处,主人公出不了地牢
            {
                return -1;
            }

        }
    }

    return maxSteps;

}

int main()
{
    //freopen("in.txt","r",stdin);
    
    cin>>n>>m;

    
    for(int i = 0; i < n; i++)
    {

        for (int j = 0; j < m; ++j)
        {
            cin>>map[i][j];
        }
    }

    
    cin>>startX;
    cin>>startY;

    
    cin>>moveNum;

    
    for (int i = 0; i < moveNum; ++i)
    {
        for(int j = 0; j < 2; j++)
        {
            cin>>moveTypes[i][j];
        }
    }
    
    Node node;
    node.x = startX;
    node.y = startY;
    map[startX][startY] = 'X';

    
    q_node.push(node);

    
    int maxStep = BFS();

    cout<<maxStep;

    return 0;
}


2. 打印出迷宫的最短路径和所有路径

给定迷宫,以及迷宫的入口点和出口点,求从入口点到出口点的最短路径和所有的路径

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>
#include <list>
#include <stack>
#include <queue>

using namespace std;

typedef struct point{
    int x;
    int y;
    point *previous;
    int step;
} point;

point dir[4] = {
    { 0, 1, NULL, 0 },
    { 1, 0, NULL, 0 },
    { 0, -1, NULL, 0 },
    { -1, 0, NULL, 0 },
};

//只有0位置可以走,到数组边缘就是走出迷宫。
//输出最短的路径和最短步数
int map[8][8] = {
    { 1, 0, 1, 1, 1, 1, 1, 1 },
    { 1, 0, 0, 0, 0, 0, 0, 1 },
    { 1, 0, 1, 1, 1, 1, 0, 1 },
    { 1, 0, 0, 0, 0, 1, 0, 0 },
    { 1, 1, 1, 1, 0, 0, 1, 1 },
    { 1, 1, 1, 1, 1, 0, 1, 1 },
    { 1, 1, 0, 0, 0, 0, 1, 1 },
    { 1, 1, 0, 1, 1, 1, 1, 1 },
};

void PrintAllPath(point *p)
{
    int shortest = p->step;
    
    cout << "可行短路径为:";
    while (p->previous != NULL)
    {
        cout << "(" << p->x << "," << p->y << ")";
        p = p->previous;
    }
    cout << "(" << p->x << "," << p->y << ")" << endl;
    cout << "路径长度为:" << shortest << endl;
}

void BFS(point startPoint)
{
    queue<point> q;
    q.push(startPoint);
    point cur;

    while (!q.empty())
    {
        cur = q.front();
        q.pop();
        map[cur.x][cur.y] = 1;

        for (int i = 0; i < 4; i++)
        {
            point nxt{ cur.x + dir[i].x, cur.y + dir[i].y, NULL, 0 };
            if (nxt.x >= 0 && nxt.x < 8 && nxt.y >= 0 && nxt.y < 8 && map[nxt.x][nxt.y] == 0)
            {
                point *tmp = new point;
                memcpy(tmp, &cur, sizeof(point));
                nxt.previous = tmp;
                nxt.step = cur.step + 1;
                map[nxt.x][nxt.y] = 1;

                if (nxt.x == 0 || nxt.x == 7 || nxt.y == 0 || nxt.y == 7)
                {
                    PrintAllPath(&nxt);//第一个到达该点的路径即为最短路径

                    //这句话注释则输出所有路径,不注释是最短路径
                    //return;
                }
                q.push(nxt);
            }
        }
    }
}

int main()
{
    point startPoint{ 0, 1, NULL, 0 };
    BFS(startPoint);

    return 0;
}

总结:
在设计点坐标时,需要几个参量:

  • 本节点x,y;如果发现本节点合法,则需要将上一节点复制一份,将其作为本节点的前驱。
  • 上一个节点x,y;
  • 已经走的步数。

配合这个左边点数据结构不断进入队列,当此节点碰到边界时则走出去,函数返回则是最短路径。
不return,则会输出所有的路径和步数。

相关文章

  • [图]BFS应用之迷宫问题

    一般迷宫类问题(求最短路径)均可用BFS求解 1. 网易 地牢逃脱 给定一个 n 行 m 列的地牢,其中 ‘.’ ...

  • 【算法常用模板】总结(更新中)

    搜索类 图类 排序类 并查集 数学类 位运算 Part1 搜索类 bfs 求迷宫问题最短路径(未验证) dfs 求...

  • 走迷宫(BFS例题)

    BFS例题---走迷宫 BFS对应数据结构queue BFS算法时间复杂度O(n^2) BFS算法不走走过的点 的...

  • 〔C++算法分析〕迷宫问题

    在还没学习bfs的情况下做到一个迷宫问题,于是的大概了解了一下DFS和BFS,就以本题为例子讲一下我初识的bfs ...

  • 走迷宫(bfs)

    后补...

  • 矩阵搜索、图相关算法整理

    dfs ,求连通块等 dfs ,指定路径搜索 BFS求迷宫距离

  • BFS及其应用

    内容概要: BFS类的实现 BFS求解连通分量 BFS求解无向图点对之间的一条最短路径 BFS判定无环图和二分图 ...

  • BFS / DFS 典型例题

    图的BFS: leetcode:1162 地图分析leetcode:542 01矩阵 树的BFS: 图的DFS: ...

  • 无向图 图的表示方法:邻接表 dfs和bfs的区别:dfs是用栈,bfs用队列 有向图 有向无环图(DAG): 不...

  • 2017-5-14 省赛模板

    简介 搜索迷宫(BFS+队列) 最短路Dijkstra+邻接矩阵Dijkstra+链式前向星+优先队列Bellma...

网友评论

      本文标题:[图]BFS应用之迷宫问题

      本文链接:https://www.haomeiwen.com/subject/yaoxsftx.html