H_On个人小站

个人站

这都被你发现了【惊
奖励你一朵小红花~


学霸的迷宫 - 广搜例题

题目链接

题目

学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗。但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫。因为班长还有妹子要陪,磨刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线。可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线。

输入

第一行两个整数 n,m 为迷宫的长宽。 接下来n行,每行 m 个数,数之间没有间隔,为0或1中的一个。 0 表示这个格子可以通过,1 表示不可以。

假设你现在已经在迷宫坐标(1,1)的地方,即左上角,迷宫的出口在(n, m)。 每次移动时只能向上下左右 4 个方向移动到另外一个可以通过的格子里,每次移动算一步。 数据保证(1, 1),(n, m)可以通过。(0<m, n<=50)

输出

第一行一个数为需要的最少步数 K。 第二行 K 个字符,每个字符 ∈{U, D, L, R},分别表示上下左右。 如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。

样例输入

3 3
001
100
110

样例输出

4
RDRD

解题思路

  • 首先用一个二位数组储存地图信息;
  • 其次用一个二位数组来储存对应位点的行动方向;
  • 之后使用双端队列容器来进行广搜操作,即:
    • 将第一个为点 (1, 1) 入队;
    • 弹出队首元素,判断“下左右上”(因为多条最短路要输出字典序最靠前的一种情况,因此在判断时直接按字典序依次判断 “DLRU”),将能走的位点(即不为“1”)存进队列,并将存入位点的地图由 “0” 更新为 “1” 使其不能再次行走;
    • 继续弹出队首进行下一轮判断,直到存入终点 (n, m) 时停止判断开始回溯查看行动情况;
  • 输出结果。

代码

注视很清晰哈

#include <iostream>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>

#define S 1<<10

using namespace std;

/** 储存位点信息 **/
struct step
{
    int x;
    int y;
    int t;
};

/** 行数和列数的变量 **/
int n, m;

/** 往 下左右上 走的坐标和对应字母的存储 **/
int cx[4] = { 1,  0,  0, -1};
int cy[4] = { 0, -1,  1,  0};
char to[4] = {'D', 'L', 'R', 'U'};

/** pot - 储存地图数据;way - 储存行动数据 **/
int pot[S][S];
int way[S][S];

/** 广搜队列,储存可能的行动路线 **/
deque<step> r;

void fd()
{
    /** 先将首位进入队列,并更新首位的地图为“1” **/
    step a;
    a.x = a.y = 1;
    a.t = 0;
    r.push_back(a);
    pot[a.x][a.y] = 1;

    /** 读取队首,然后讲周围能走的空位入队 **/
    while (!r.empty())
    {
        a = r.front();
        r.pop_front();
        for (int i=0; i<4; i++)
        {
            step b;
            b.x = a.x + cx[i];
            b.y = a.y + cy[i];
            b.t = a.t + 1;
            if (!pot[b.x][b.y])
            {
                r.push_back(b);
                pot[b.x][b.y] = 1;
                way[b.x][b.y] = i;
            }

            /** 如果遇到出口位点则回溯查看路径 **/
            if (b.x==n && b.y==m)
            {
                stack<char> w;
                cout << b.t << endl;
                while (b.x!=1 || b.y!=1)
                {
                    int tw = way[b.x][b.y];
                    w.push(to[tw]);
                    b.x -= cx[tw];
                    b.y -= cy[tw];
                }
                while (!w.empty()) cout << w.top(), w.pop();
                cout << endl;
                /** 注意这里一定要 return 不然会继续循环直到 r 为空 **/
                /** 可能会会导致答案错误 **/
                return ;
            }
        }
    }

}

int main()
{
    /** 将地图所有位点置为 “1”  **/
    /** 既能初始化地图,又能防止判断路线出界  **/
    memset(pot, 1, sizeof(pot));

    /** 输入地图的行数和列数 **/
    cin >> n >> m;

    /** 输入地图,使用 %1d 直接获取一个整数字符,方便判断和处理 **/
    for (int i=1; i<=n; i++) for (int j=1; j<=m; j++)
        scanf("%1d", &pot[i][j]);

    /** 寻找路径 **/
    fd();
    return 0;
}