描述
一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。
给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。
输入
第一行是两个整数,R和C,代表迷宫的长和宽。( 1<= R,C <= 40)
接下来是R行,每行C个字符,代表整个迷宫。
空地格子用’.‘表示,有障碍物的格子用’#‘表示。
迷宫左上角和右下角都是’.’。
输出
输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。
样例输入
5 5
..###
#....
#.#.#
#.#.#
#.#..
样例输出
9
#include <iostream>
#include <queue>
#define P pair<int, int>
using namespace std;
//记录下当前状态, 从前往后搜索值为1,从后往前搜索值为2,如果某状态下,当前节点和准备扩展节点的状态相加为3,说明相遇
queue <P> q1, q2;
int r, c, ans;
int dis[45][45]; //最短路径
int vst[45][45];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
char m[45][45];
void dbfs() {
bool flag;
q1.push(P(1, 1)), dis[1][1] = 1, vst[1][1] = 1; //从前搜
q2.push(P(r, c)), dis[r][c] = 1, vst[r][c] = 2; //从后搜
while(!q1.empty() && !q2.empty()) {
int x0, y0;
if(q1.size() > q2.size()) { //每次扩展搜索树小的队列 flag=1扩展前搜的队列,flag=0扩展后搜的队列
x0 = q2.front().first, y0 = q2.front().second;
q2.pop();
flag = 0;
}else {
x0 = q1.front().first, y0 = q1.front().second;
q1.pop();
flag = 1;
}
for(int i = 0; i < 4; i++) {
int nx = x0 + dx[i];
int ny = y0 + dy[i];
if(nx >= 1 && nx <= r && ny >= 1 && ny <= c && m[nx][ny] == '.')
{
if(flag == 0 && vst[nx][ny] ==2)
continue;
if(flag == 1 && vst[nx][ny] ==1)
continue;
if(!dis[nx][ny] )
{
dis[nx][ny] = dis[x0][y0] + 1;
vst[nx][ny] = vst[x0][y0];
if(flag) q1.push(P(nx, ny));
else q2.push(P(nx, ny));
}
else
{
ans = dis[nx][ny] + dis[x0][y0];
//搜索重合,即是答案,即从起点走到终点的最短距离
return;
}
}
}
}
}
int main() {
cin >> r >> c;
for(int i = 1; i <= r; i++)
for(int j = 1; j <= c; j++)
cin >> m[i][j];
dbfs();
cout << ans << "\n";
return 0;
}