题目链接: AcWing 1240 地牢大师
题意: 给定一个三维空间,一个起点和终点,还有若干障碍物,人物从起点开始,只能往上下左右前后六个方向移动,问能否达到终点,若能,输出最短步数
解题思路:
这是裸的广搜,只是把空间换成了三维,所以和二维相比,区别就在于建图时要用三维数组,控制移动时,也有三个偏移量,其它地方直接套用广搜模板即可
代码如下:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int l, r, c; // 分别是层数,每层的行数、列数
int res[N][N][N]; // 计算步数,顺便作为标记
char g[N][N][N]; // 建图
struct Point {
int z, x, y;
} st, ed;
bool check(int z, int x, int y) {
if (z < 1 || z > l) {
return false;
}
if (x < 1 || x > r) {
return false;
}
if (y < 1 || y > c) {
return false;
}
if (res[z][x][y] != -1) {
return false;
}
if (g[z][x][y] == '#') {
return false;
}
return true;
}
void bfs() {
queue<Point> Q;
Q.push(st);
res[st.z][st.x][st.y] = 0;
// 这是几乎是唯一的区别
// 一共六个偏移量,加入上下移动即可
int dx[6] = {1, 0, -1, 0, 0, 0};
int dy[6] = {0, 1, 0, -1, 0, 0};
int dz[6] = {0, 0, 0, 0, -1, 1};
while ((int) Q.size() > 0) {
auto t = Q.front();
Q.pop();
for (int i = 0; i < 6; i++) {
int z = t.z + dz[i];
int x = t.x + dx[i];
int y = t.y + dy[i];
if (check(z, x, y)) {
Q.push({z, x, y});
res[z][x][y] = res[t.z][t.x][t.y] + 1;
}
}
}
}
int main() {
while(scanf("%d%d%d", &l, &r, &c) && l){
// 因为有多组输入,每次标记数组都要重新赋值
memset(res, -1, sizeof res);
for (int i = 0; i < l; i++) {
for (int j = 0; j < r; j++) {
string s;
cin >> s;
for (int k = 0; k < c; k++) {
// 这是我个人习惯,在图的问题中,把坐标都从1开始
g[i + 1][j + 1][k + 1] = s[k];
if (s[k] == 'S') {
st = {i + 1, j + 1, k + 1};
} else if (s[k] == 'E') {
ed = {i + 1, j + 1, k + 1};
}
}
}
}
bfs();
// 太长了,用 ans 保存着
int ans = res[ed.z][ed.x][ed.y];
if(ans != -1) printf("Escaped in %d minute(s).\n", ans);
else printf("Trapped!\n");
}
return 0;
}
我靠,我跟你一模一样的做法,为啥内存超限,还是第一次碰到
有可能是代码实现的时候没有记录走过的点导致重复入队,队列过长吧。
谢谢提醒,确实是重复入队的问题
我也是,想着想着就忘了那里了
while(Q.size()){
auto t = Q.front();
Q.pop();
这步意思是什么啊,为什么有这步
广搜的固定模板,队列的使用方法。
g[i + 1][j + 1][k + 1] = s[k];这个是什么意思呢,k不是指列数吗
这里就是建立一个三维的图呀。
当队列不为空的时候,记录队首第一个元素t,第一个元素出队。
st, ed; 是什么意思呀
起点start和终点end
不愧是你。。。