给定一个 n × m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1 ,其中 0 表示可以走的路,1 表示不可通过的墙壁。
最初,有一个人位于左上角 (1, 1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 ( n, m ) 处,至少需要移动多少次。
数据保证 (1, 1) 处和 ( n, m ) 处的数字为 0 ,且一定至少存在一条通路。
Input
第一行包含两个整数 n 和 m 。1 ≤ n, m ≤ 100
接下来 n 行,每行包含 m 个整数( 0 或 1 ),表示完整的二维数组迷宫。
Output
输出一个整数,表示从左上角移动至右下角的最少移动次数以及移动路径。
Sample Input
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
8
1 1
2 1
3 1
3 2
3 3
3 4
3 5
4 5
5 5
蛛丝:就是在普通的bfs遍历二维迷宫的时候新开一个数组记录该点是经过了哪个变化而来,有4个变化,例如样例里面坐标(2,1)的点也就是d[2][1]的点是d[1][1]经过dx[2],dy[2]得到,就将2作为st[2][1]的值输入,最后遍历到终点时根据st数组的值回溯到d[1][1],将路上的节点坐标存入一个vector数组后倒序输出就行了,就是从起点到终点的路上的坐标的点了
如果是换成求任意两点之间的距离也很简单,改一下起点终点的值就差不多了,代码变动不大。
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <cmath>
#include <stack>
using namespace std;
const int N=1010;
typedef pair<int ,int>PII;
int s1,s2,t1,t2;
int st[N][N];
int d[N][N];
int p[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int dist[N][N];
int n,m;
int bfs()
{
memset(dist,-1,sizeof dist);
memset(st,-1,sizeof st);
queue<PII>que;
que.push({1,1});
st[1][1]=-1;
dist[1][1]=0;
while(que.size())
{
auto t=que.front();
que.pop();
for(int i=0;i<4;i++)
{
int x=t.first+dx[i],y=t.second+dy[i];
if(x>=1&&x<=n&&y>=1&&y<=m&&dist[x][y]==-1&&d[x][y]==0)
{
st[x][y]=i;//记录该点是经过哪个操作得到的
dist[x][y]=dist[t.first][t.second]+1;
que.push({x,y});
}
}
}
return dist[n][n];
}
void ch(int x,int y) //输出路径
{
vector<PII>v;
while(st[x][y]!=-1)
{
int a=x,b=y;
v.push_back({x,y});
x=x-dx[st[a][b]];
y=y-dy[st[a][b]];
}
v.push_back({1,1});
for(int i=v.size()-1;i>=0;i--)
cout<<v[i].first<<' '<<v[i].second<<endl;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&d[i][j]);
}
}
cout<<bfs()<<endl;
ch(n,n);
return 0;
}