【例题3】立体推箱子
Link
解题思路
记录状态时将坐标和木块状态一起记录
(
q
[
x
]
[
y
]
[
t
]
)
(q[x][y][t])
(q[x][y][t])
对于2状态,坐标默认是下面那一块
对于3状态,坐标默认是右边那一块
有几个需要注意的旋转时坐标的改变
Code
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int xw[4][5] = {{}, {-1, 0, 2}, {-2, 0, 1}, {-1, 0, 1}};//把坐标的改变预处理出来
const int yw[4][5] = {{}, {0, 2, 0, -1}, {0, 1, 0, -1}, {0, 1, 0, -2}};
const int tw[4][5] = {{}, {2, 3, 2, 3}, {1, 2, 1, 2}, {3, 1, 3, 1}};
int n, m, s[510][510][5], q[750100][3], h, t, v[510][510][5];
int sx, sy, st, ex, ey, et, ans;
char a[510][510];
void initial() {
st = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (a[i][j] == 'X' && !st) {
if (a[i + 1][j] == 'X')//状态2
sx = i + 1, sy = j, st = 2;
else
if (a[i][j + 1] == 'X')//状态3
sx = i, sy = j + 1, st = 3;
else
sx = i, sy = j, st = 1;//只有一个‘X’是状态1
}
if (a[i][j] == 'O')
ex = i, ey = j, et = 1;
}
}
bool check(int x, int y, int t) {
if (x < 0 || x > n || y < 0 || y > m)
return 0;
if (t == 1) {
if (a[x][y] == 'E' || a[x][y] == '#')//不可以立在易碎地面上
return 0;
}
if (t == 2) {
if (a[x][y] == '#' || a[x - 1][y] == '#')
return 0;
}
if (t == 3) {
if (a[x][y] == '#' || a[x][y - 1] == '#')
return 0;
}
return 1;
}
bool BFS() {
h = t = s[sx][sy][st] = 0;
q[++t][0] = sx, q[t][1] = sy, q[t][2] = st;
while (h++ < t) {
for (int i = 0; i < 4; i++) {
int xx = q[h][0] + xw[q[h][2]][i];
int yy = q[h][1] + yw[q[h][2]][i];
int tt = tw[q[h][2]][i];
if (check(xx, yy, tt) && //判断当前的(xx, yy, tt)可不可行
!v[xx][yy][tt]) {//判断(xx, yy, tt)走没走过
s[xx][yy][tt] = s[q[h][0]][q[h][1]][q[h][2]] + 1;//记录步数
v[xx][yy][tt] = 1, q[++t][0] = xx, q[t][1] = yy, q[t][2] = tt;
if (xx == ex && yy == ey && tt == et) {//走到‘O’上
printf("%d\n", s[ex][ey][et]);
return 0;
}
}
}
}
return 1;
}
int main() {
scanf("%d%d", &n, &m);
while (n && m) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin>>a[i][j];
initial();//预处理
if (BFS())
printf ("Impossible\n");
//*****************************************
ans = 0;
memset(v, 0, sizeof(v));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = '\0';
//清空*************************************
scanf("%d%d", &n, &m);
}
}