一、Problem
Storekeeper is a game in which the player pushes boxes around in a warehouse trying to get them to target locations.
The game is represented by a grid of size m x n, where each element is a wall, floor, or a box.
Your task is move the box ‘B’ to the target position ‘T’ under the following rules:
- Player is represented by character ‘S’ and can move up, down, left, right in the grid if it is a floor (empy cell).
- Floor is represented by character ‘.’ that means free cell to walk.
- Wall is represented by character ‘#’ that means obstacle (impossible to walk there).
- There is only one box ‘B’ and one target cell ‘T’ in the grid.
- The box can be moved to an adjacent free cell by standing next to the box and - then moving in the direction of the box. This is a push.
- The player cannot walk through the box.
Return the minimum number of pushes to move the box to the target. If there is no way to reach the target, return -1.
Input: grid = [["#","#","#","#","#","#"],
["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#",".","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
Output: 3
Explanation: We return only the number of times the box is pushed.
二、Solution
方法一:bfs
- 人先走,正常 bfs 即可,如果在換方向時碰到箱子,那麼這個方向時不可行的,因爲我只是想枚舉人的座標。
- 如果找到相鄰位置是箱子(曼哈頓距爲 1),那麼計算出箱子在哪個方向,然後就是將箱子的位置的同方向 k 的下一個位置 push_back 到雙端隊列中,此時距離記得加 1(ps:人移動時的距離是不用加 1)
細節:
- 人的位置總是在隊列中的前面,因爲這樣能快速訪問到箱子,而且可以枚舉到人從各個方向將箱子推到終點的最短距離,避免疏漏。
- 因爲有箱子的存在,所以會有兩個座標的狀態表示。
class Solution {
int n, m;
final static int[][] d = { {1,0},{0,-1},{0,1},{-1,0} };
public int minPushBox(char[][] g) {
n = g.length; m = g[0].length;
int[][][][] f = new int[n][m][n][m];
int Px = 0, Py = 0, Bx = 0, By = 0, Tx = 0, Ty = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (g[i][j] == 'S') {
Px = i; Py = j;
g[i][j] = '.';
} else if (g[i][j] == 'B') {
Bx = i; By = j;
g[i][j] = '.';
} else if (g[i][j] == 'T') {
Tx = i; Ty = j;
g[i][j] = '.';
}
}
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
f[i][j][i][j] = -1;
Deque<Pos> q = new ArrayDeque<>();
q.add(new Pos(Px, Py, Bx, By));
f[Px][Py][Bx][By] = 0;
while (!q.isEmpty()) {
Pos cur = q.poll();
int px = cur.px, py = cur.py, bx = cur.bx, by = cur.by;
if (bx == Tx && by == Ty) {
// System.out.println(111);
return f[px][py][bx][by];
}
for (int k = 0; k < 4; k++) {
int npx = px + d[k][0], npy = py + d[k][1];
// System.out.println(npx + " " + npy);
if (!inArea(npx, npy) || g[npx][npy] != '.')
continue;
if (npx == bx && npy == by || f[npx][npy][bx][by] >= 0)
continue;
q.addFirst(new Pos(npx, npy, bx, by));
f[npx][npy][bx][by] = f[px][py][bx][by];
}
if (Math.abs(px-bx) + Math.abs(py-by) == 1) {
// System.out.println(111);
int k;
for (k = 0; k < 4; k++) {
int nx = px + d[k][0], ny = py + d[k][1];
if (nx == bx && ny == by)
break;
}
int nbx = bx + d[k][0], nby = by + d[k][1];
if (!inArea(nbx, nby) || g[nbx][nbx] != '.' || f[bx][by][nbx][nby] >= 0)
continue;
q.add(new Pos(bx, by, nbx, nby));
f[bx][by][nbx][nby] = f[px][py][bx][by] + 1;
// System.out.println(f[bx][by][nbx][nby]);
}
}
return -1;
}
boolean inArea(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
class Pos {
int px, py, bx, by;
public Pos(int px, int py, int bx, int by) {
this.px = px;
this.py = py;
this.bx = bx;
this.by = by;
}
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,