[图]BFS应用之迷宫问题

一般迷宫类问题(求最短路径)均可用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,则会输出所有的路径和步数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 在搜索算法中,最为简单的并且最为重要的要数BFS(宽度优先搜素),DFS(深度优先搜索)两种算法。搜索领域中的高深...
    叶俊贤阅读 6,391评论 0 1
  • 题目描述 给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (...
    水木年华_d444阅读 445评论 0 0
  • 现实生活中有很大一类问题可以用简洁明了的图论语言来描述,可以转化为图论问题。 相关定义 图可以表示为G=(V, E...
    芥丶未央阅读 1,561评论 0 7
  • 我在想 你是否看到了我呢 我刚刚向你招手 不知你,是否看见了呢 我从湖边经过 水光粼粼的湖面,泛着光 我踮着脚尖,...
    木庭兮阅读 202评论 0 1
  • 本周阅读了第四章 的第十一讲后半部分 人类误判心理学 1、普朗克说,唯有新的一代成长起来,较少受到旧理论毒害的他...
    AskYp阅读 546评论 5 0