1263. 推箱子
「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。
游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。
现在你将作为玩家参与游戏,按规则将箱子 'B' 移动到目标位置 'T' :
玩家用字符 'S' 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
地板用字符 '.' 表示,意味着可以自由行走。
墙用字符 '#' 表示,意味着障碍物,不能通行。 
箱子仅有一个,用字符 'B' 表示。相应地,网格上有一个目标位置 'T'。
玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
玩家无法越过箱子。
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。
示例 1:

```txt
输入:grid = [["#","#","#","#","#","#"],
         ["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#",".","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
输出:3
解释:我们只需要返回推箱子的次数。
```
示例 2:
```txt
输入:grid = [["#","#","#","#","#","#"],
         ["#","T","#","#","#","#"],
["#",".",".","B",".","#"],
["#","#","#","#",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
输出:-1
```
示例 3:
```txt
输入:grid = [["#","#","#","#","#","#"],
["#","T",".",".","#","#"],
["#",".","#","B",".","#"],
["#",".",".",".",".","#"],
["#",".",".",".","S","#"],
["#","#","#","#","#","#"]]
输出:5
解释:向下、向左、向左、向上再向上。
```
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 20
grid 仅包含字符 '.', '#',  'S' , 'T', 以及 'B'。
grid 中 'S', 'B' 和 'T' 各只能出现一个。
">
    
      
    
    
    
    
        题目
1263. 推箱子
「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。
游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。
现在你将作为玩家参与游戏,按规则将箱子 'B' 移动到目标位置 'T' :
-   玩家用字符 
'S' 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。 
-   地板用字符 
'.' 表示,意味着可以自由行走。 
-   墙用字符 
'#' 表示,意味着障碍物,不能通行。  
-   箱子仅有一个,用字符 
'B' 表示。相应地,网格上有一个目标位置 'T'。 
-   玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
 
-   玩家无法越过箱子。
 
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。
示例 1:
![]()
1 2 3 4 5 6 7 8
   | 输入:grid = [["#","#","#","#","#","#"],              ["#","T","#","#","#","#"],              ["#",".",".","B",".","#"],              ["#",".","#","#",".","#"],              ["#",".",".",".","S","#"],              ["#","#","#","#","#","#"]] 输出:3 解释:我们只需要返回推箱子的次数。
   | 
 
示例 2:
1 2 3 4 5 6 7
   | 输入:grid = [["#","#","#","#","#","#"],              ["#","T","#","#","#","#"],              ["#",".",".","B",".","#"],              ["#","#","#","#",".","#"],              ["#",".",".",".","S","#"],              ["#","#","#","#","#","#"]] 输出:-1
   | 
 
示例 3:
1 2 3 4 5 6 7 8
   | 输入:grid = [["#","#","#","#","#","#"],              ["#","T",".",".","#","#"],              ["#",".","#","B",".","#"],              ["#",".",".",".",".","#"],              ["#",".",".",".","S","#"],              ["#","#","#","#","#","#"]] 输出:5 解释:向下、向左、向左、向上再向上。
   | 
 
提示:
-   
m == grid.length 
-   
n == grid[i].length 
-   
1 <= m, n <= 20 
-   
grid 仅包含字符 '.', '#',  'S' , 'T', 以及 'B'。 
grid 中 'S', 'B' 和 'T' 各只能出现一个。 
题解
方法一:
思路
我们需要箱子到目标点的最小距离,箱子的移动方向有四种但是有些位置的移动方向不可用。
我们注意到每次箱子移动完后,人的位置就代替了之前的箱子的位置。
那么我们可以用状态$f_{x,y,z}$代表箱子在坐标(x,y)位置且人在坐标(x+(z-1)%2, y+(z-2)%2)的最小移动次数。
(z取值在0到3,这样人的位置就有4种(x-1,y), (x,y-1), (x+1,y), (x,y+1))
状态的转移可以用BFS来完成。
我们需要先找到初始状态,也就是人一开始可以在箱子四周的位置个数。然后加入队列。
在队列中每次出队一个状态,我们考虑可以转移到哪些状态:
若出队$f_{i,j,z}$,能转移的状态为$f_{i’,j’,z’}$,则$(i’,j’)$是$(i,j)$的四周的一个位置且不能越界,不能为墙。然后$z$和$z’$在不经过$(i,j)$必须连通。
数据范围n最多20,m最多20。
总状态数4nm个,每次状态转移方向有4个,每个需要用BFS花$O(nm)$时间来检测连通性。
时间复杂度为$O(n^2m^2)$
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
   | class Solution { public:                    const int INF = 0x3f3f3f3f;     int minPushBox(vector<vector<char>>& g) {         int n = g.size(), m = g[0].size();         int box_x, box_y, peo_x, peo_y, tar_x, tar_y;         for (int i=0; i<n; i++) {             for (int j=0; j<m; j++) {                 if (g[i][j] == 'S') {                     peo_x = i, peo_y = j, g[i][j] = '.';                 }                 if (g[i][j] == 'B') {                     box_x = i, box_y = j, g[i][j] = '.';                 }                 if (g[i][j] == 'T') {                     tar_x = i, tar_y = j, g[i][j] = '.';                 }             }         }                                                               auto check = [&](int x, int y, int p1, int p2) {             int sx = x+(p1-1)%2, sy = y+(p1-2)%2;             int tx = x+(p2-1)%2, ty = y+(p2-2)%2;             if (sx<0 || sx>=n || sy<0 || sy>=m || g[sx][sy] != '.') return false;             if (tx<0 || tx>=n || ty<0 || ty>=m || g[tx][ty] != '.') return false;             vector<vector<int>> vis(n, vector<int>(m,0));             vis[sx][sy] = 1;             queue<pair<int,int>> q;             q.emplace(sx, sy);             while (q.size()) {                 auto [a, b] = q.front(); q.pop();                 if (a == tx && b == ty) {                     return true;                 }                 for (int i=0; i<4; i++) {                     int ma = a+(i-1)%2, mb = b+(i-2)%2;                     if (ma<0 || ma>=n || mb<0 || mb>=m || ma==x && mb==y ||                      g[ma][mb]=='#' || vis[ma][mb])                         continue;                     vis[ma][mb] = 1;                     q.emplace(ma, mb);                 }             }             return false;         };         auto get_start = [&]() {             vector<vector<int>> dis(n, vector<int>(m, INF));             dis[peo_x][peo_y] = 0;             queue<pair<int,int>> q;             q.emplace(peo_x, peo_y);             while (q.size()) {                 auto [x, y] = q.front(); q.pop();                 for (int i=0; i<4; i++) {                     int mx = x+(i-1)%2;                     int my = y+(i-2)%2;                     if (mx<0 || mx>=n || my<0 || my>=m ||                      mx == box_x && my == box_y || g[mx][my] == '#' || dis[mx][my] != INF)                          continue;                     dis[mx][my] = dis[x][y] + 1;                     q.emplace(mx, my);                 }             }             vector<tuple<int,int,int>> rt;             for (int i=0; i<4; i++) {                 int mx = box_x+(i-1)%2;                 int my = box_y+(i-2)%2;                 if (mx<0 || mx>=n || my<0 || my>=m || g[mx][my] == '#' || dis[mx][my] == INF)                      continue;                 rt.emplace_back(box_x, box_y, i);             }             return rt;         };         queue<tuple<int,int,int>> q;         int vis[22][22][5];         memset(vis, 0, sizeof(vis));         auto s = get_start();         for (auto [i,j,k]: s) {                          q.emplace(i,j,k);             vis[i][j][k] = 1;         }         int stp = 0;         while (q.size()) {             int sz = q.size();             for (int _=0; _<sz; _++) {                 auto [x, y, z] = q.front(); q.pop();                                  if (x == tar_x && y == tar_y) return stp;                 for (int i=0; i<4; i++) {                     int mx = x+(i-1)%2;                     int my = y+(i-2)%2;                     if (!check(x,y,z,(i+2)%4) || mx<0 || mx>=n || my<0 || my>=m                      || g[mx][my] == '#'|| vis[mx][my][(i+2)%4])                          continue;                                                                vis[mx][my][(i+2)%4] = 1;                     q.emplace(mx,my,(i+2)%4);                 }             }             stp++;         }         return -1;     } };
  |