题目描述:
一个网格迷宫由n行m列的单元格组成,每个单元格要么是空地(用1表示),要么是障碍物(用0来表示)。你的任务是找一条从起点到终点的最短步数和移动序列,其中UDLR表示上下左右操作。任何时候都不能在障碍物格子中,也不能走到迷宫之外。起点和终点保证都是空地。n,m<100。
样例输入:
6 5
11011
10111
10100
10111
11101
11111
样例输出:
9
DDDDDRRRR
解题思路:
较上一个文章来说,只是多了输出路径,这里既然题目没规定入口出口,为了方便起见,我人为的把入口和出口规定为左上角和右下角。记录路径即需要知道终点是由那个点走到的,而这个点的上一个点也需要知道……所以就记录下每个点的父节点和相应的操作,然而准备输出路径的时候又遇到了一个问题:从出口一步步向上寻找,是一个倒着的,怎么才能正着输出呢?先进后出这个特点是栈对应的特点,而递归类似栈,所以利用递归的方式,达到按顺序输出的目的。
代码:
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
char mmap[10][10]={};
int vis[10][10]={};
int n,m;
int xx[4]={1,0,0,-1};//下、右、左、上
int yy[4]={0,1,-1,0};
struct node
{
int x,y;
int t;//t表示走到这个格子用的步数
};
struct father
{
int x,y;//当前格子的父节点坐标
char cz;//由什么操作到达的这个格子
};
queue<node> q;
node s,f;
father lj[10][10];//记录路径
int bfs()
{
int i,j;
s.x=0;s.y=0;s.t=0;
f.x=n-1;f.y=m-1;
q.push(s);
lj[s.x][s.y].x=1000;//因为m,n<=100
lj[s.x][s.y].y=1000;
lj[s.x][s.y].cz=0;
vis[s.x][s.y]=1;//标为已经访问过
while(!q.empty())
{
node now=q.front();
q.pop();
for(i=0;i<4;++i)
{
node New;
New.x=now.x+xx[i];
New.y=now.y+yy[i];
New.t=now.t+1;
if(New.x<0||New.y<0||New.x>=n||New.y>=m||vis[New.x][New.y]||mmap[New.x][New.y]=='0')//下标越界或者访问过或者是障碍物
continue;
q.push(New);
lj[New.x][New.y].x=now.x;
lj[New.x][New.y].y=now.y;
if(i==0) lj[New.x][New.y].cz='D';
else if(i==1) lj[New.x][New.y].cz='R';
else if(i==2) lj[New.x][New.y].cz='L';
else if(i==3) lj[New.x][New.y].cz='U';
vis[New.x][New.y]=1;
if(New.x==f.x&&New.y==f.y) return New.t;//到达终点
}
}
return -1;
}
void dfs(int x, int y)
{
if(x==0&&y==0) return;//找到父节点是起点的格子了
else
dfs(lj[x][y].x,lj[x][y].y);
printf("%c",lj[x][y].cz);
}
int main()
{
int i,j,ans;
scanf("%d%d",&n,&m);
for(i=0;i<n;++i)
{
scanf("%s",mmap[i]);
}
ans=bfs();
if(ans<0) printf("error");
else
{
printf("%d\n",ans);
dfs(n-1,m-1);//从终点开始找他的父节点
}
return 0;
}