Description
有一个N*M的格子迷宫,1代表该格子为墙,不能通过,0代表可以通过,另外,在迷宫中
有一些传送门,走到传送门的入口即会自动被传送到传送门的出口(一次传送算1步)。人在迷宫中可以尝试
上下左右四个方向移动。现在给定一个迷宫和所有传送门的出入口,以及起点和终点,
问最少多少步可以走出迷宫。如果不能走出迷宫输出“die”。
输入格式
该程序为多CASE,第1行为CASE的数量
每一个CASE,第1行为两个数N(行)和M(列)
然后N行每行M个数
之后是一个数W,为传送门的数量
之后每行一个传送门的入口坐标c1(行),r1(列)和出口坐标c2,r2
之后是起点坐标和终点坐标sc(行) sr(列) ec(行) er(列)
注:传送门出入口和起点坐标和终点坐标不会出现在墙的位置
所有数字不超过100
输出格式
如题
输入样例
2
4 3
011
011
110
110
1
1 0 2 2
0 0 3 2
2 2
01
10
0
0 0 1 1
输出样例
3
die
一、深度搜索DFS->由于数据量较大所以超时
//超时:深度搜索
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int N, M, W, result = 0;
char map[200][200] = { 0 };
int v[200][200] = { 0 }, dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
int sc, sr, ec, er;
struct door
{
int c1;
int r1;
int c2;
int r2;
} door[100];
int min_step = 1e9;
void dfs(int x, int y, int step)
{
//检查当前位置是否是传送点入口
int j;
for (j = 0; j < W; j++)
{
if (x == door[j].c1 && y == door[j].r1)
{
if (v[door[j].c2][door[j].r2] == 1)
return;
x = door[j].c2;
y = door[j].r2;
step++;
v[x][y] = 1;
break;
}
}
if (x == ec && y == er)
{
min_step = min_step < step ? min_step : step;
result = 1;
return;
}
int i;
for (i = 0; i < 4; i++)
{
int cur_x = x + dx[i], cur_y = y + dy[i];
if (cur_x >= 0 && cur_x < N && cur_y >= 0 && cur_y < M && map[cur_x][cur_y] == '0' && v[cur_x][cur_y] == 0)
{
v[cur_x][cur_y] = 1;
dfs(cur_x, cur_y, step + 1);
v[cur_x][cur_y] = 0;
}
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
result = 0;
min_step = 1e9;
memset(v, 0, sizeof(v));
memset(door, 0, sizeof(door));
int i, j;
scanf("%d%d", &N, &M); getchar();
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
scanf("%c", &map[i][j]);
getchar();
}
cin >> W;
for (i = 0; i < W; i++)
cin >> door[i].c1 >> door[i].r1 >> door[i].c2 >> door[i].r2;
cin >> sc >> sr >> ec >> er;
v[sc][sr] = 1;
dfs(sc, sr, 0);
if (result == 0)
cout << "die" << endl;
else
cout << min_step << endl;
}
return 0;
}
二、广度搜索BFS->AC
/*
思路解析:
广度搜索用的数据结构为队列,如果是普通的迷宫问题,其实有个特点,就是从每一步延伸出来下一步的坐标,都是当前步数加一, 所以可以统一的将每一步所延伸出来的步数一起出队,len = r - f; len即为上一步延伸出来的可走的位置数,len个位置全部出队,则步数step++; 但是这个本质是一个一个位置出队,下一步的步数是当前步的步数加一,即可以用结构体Pos封装一下x、y坐标外,再加入一个记录当前步数的变量,以便用队列统计每一步的步数,即q[r].step = q[f].step+1,理解为 由当前位置延伸的位置的步数 为 当前位置的步数 加一,借此可以统计走到地图中每一个位置的步数,又因为是广度搜索,所以到达终点的一定是最短路径,所以直接判断队头是否是终点即可。其他的判断则是判断当前位置是否是传送门,如果是,则判断传送点的出口有没有走过,如果走过,就不必继续再走了,如果没有走过,那么就可以就将出口坐标入队,并且标记走过。这样不用for循环统一将某一步的位置出队,即可将传送点的情况跟普通位置的情况出队入队统一起来,计算最短步数
*/
//广搜AC
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int N, M, W, result = 0;
char map[200][200] = { 0 };
int v[200][200] = { 0 }, isdoor[200][200] = { 0 }, dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };
int sc, sr, ec, er;//入口、出口行列数
//传送点入口出口结构体
struct door
{
int c1;
int r1;
int c2;
int r2;
} door[105];
//记录结构体
typedef struct pos
{
int x;//记录当前点的行数
int y;//记录当前点的列数
int step;//记录步数
} Pos;
//广搜bfs
int bfs()
{
//创造静态队列,记录位置和到达当前位置的步数
Pos q[100000] = { 0 };//注意队列数组要开大一点,否则会报错
int f, r;
f = 0, r = 0;
q[r].x = sc, q[r].y = sr,q[r].step = 0;
r++;
while (f != r)
{
//判断当前点是否是终点,如果是终点,则返回步数
if (q[f].x == ec && q[f].y == er)
return q[f].step;
//如果当前点为传送点
if (isdoor[q[f].x][q[f].y] != 0)
{
//记录数组存储传送门的下标方便访问
int out_index = isdoor[q[f].x][q[f].y];
int out_x = door[out_index].c2;
int out_y = door[out_index].r2;
//如果出口是墙 或者 不在地图内 或者 已经被走过,则将队头出队
if (map[out_x][out_y] == '1' || out_x < 0 || out_x >= N || out_y < 0 || out_y >= M || v[out_x][out_y] == 1)
{
f++;
continue;
}
//把传送门的出口坐标入队
q[r].x = out_x;
q[r].y = out_y;
q[r].step = q[f].step + 1;
r++;
v[out_x][out_y] = 1;//标记传送门出口走过
}
else //如果当前点不是出口也不是传送点,则往四个方向走,并且将可以走的点入队
{
int i;
for (i = 0; i < 4; i++)
{
int cur_x = q[f].x + dx[i], cur_y = q[f].y + dy[i];
if (cur_x >= 0 && cur_x < N && cur_y >= 0 && cur_y < M && map[cur_x][cur_y] == '0' && v[cur_x][cur_y] == 0)
{
v[cur_x][cur_y] = 1;//标记当前位置走过
q[r].x = cur_x;
q[r].y = cur_y;
q[r].step = q[f].step + 1;
r++;
}
}
}
f++;//队头出队
}
return -1;
}
int main()
{
int T;
cin >> T;
while (T--)
{
memset(v, 0, sizeof(v));
memset(isdoor, 0, sizeof(isdoor));
memset(door, 0, sizeof(door));
//读入行和列
scanf("%d%d", &N, &M);
getchar();
//读入路和墙,即地图
int i, j;
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
scanf("%c", &map[i][j]);
getchar();
}
//读入传送门个数
scanf("%d",&W);
//读入传送门入口和出口坐标,同时标记传送门的位置
for (i = 1; i <= W; i++)
{
cin >> door[i].c1 >> door[i].r1 >> door[i].c2 >> door[i].r2;
isdoor[door[i].c1][door[i].r1] = i;//标记为是传送点
}
//读入入口和出口坐标
cin >> sc >> sr >> ec >> er;
//标记入口已经走过
v[sc][sr] = 1;
//广度搜索
int step = bfs();
if (step == -1)
printf("die\n");
else
printf("%d\n", step);
}
return 0;
}