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