【Leetcode】1263. Minimum Moves to Move a Box to Their Target Location

题目地址:

https://leetcode.com/problems/minimum-moves-to-move-a-box-to-their-target-location/

给定一个二维地图,例如:
请添加图片描述
地图以 m × n m\times n m×n的字符矩阵给出,B代表箱子的初始位置,T代表箱子的目标位置,S代表人的初始位置,#代表障碍物,人和箱子都不能进入,.代表空地。除了出界、障碍物以外的位置,人和箱子都可以进入。求将箱子推到目标位置的箱子的最少移动步数。

思路是双端队列BFS。设状态为 ( x 1 , y 1 , x 2 , y 2 ) (x_1,y_1,x_2,y_2) (x1,y1,x2,y2) ( x 1 , y 1 ) (x_1,y_1) (x1,y1)代表箱子的位置, ( x 2 , y 2 ) (x_2,y_2) (x2,y2)代表人的位置。那么初始状态已知,而其能转移到的状态可以分成两种情况,首先考虑人走一步,那人有三个方向可以走(去掉出界、障碍物等等非法情况),转移的代价为 0 0 0(因为箱子没动),然后再考虑箱子走一步,这种情况只有在人恰好在箱子旁边的时候才能转移到,并且箱子移动到的地方不能非法,这种转移的代价为 1 1 1。那么其实就是在 01 01 01图上求最短路,可以用双端队列BFS来做。代码如下:

class Solution {
 public:
  struct State {
    // box
    int x1, y1;
    // man
    int x2, y2;
  };

  const int N = 20;

  int minPushBox(vector<vector<char>>& g) {
    int m = g.size(), n = g[0].size();
    State begin;
    for (int i = 0; i < m; i++)
      for (int j = 0; j < n; j++)
        if (g[i][j] == 'B')
          begin.x1 = i, begin.y1 = j;
        else if (g[i][j] == 'S')
          begin.x2 = i, begin.y2 = j;

    int dist[N][N][N][N];
    bool vis[N][N][N][N];
    memset(dist, 0x3f, sizeof dist);
    dist[begin.x1][begin.y1][begin.x2][begin.y2] = 0;
    memset(vis, 0, sizeof vis);
    deque<State> dq;
    dq.push_back(begin);
    static int d[] = {-1, 0, 1, 0, -1};
    while (dq.size()) {
      auto t = dq.front();
      dq.pop_front();
      int x1 = t.x1, y1 = t.y1, x2 = t.x2, y2 = t.y2;
      int dis = dist[x1][y1][x2][y2];
      if (g[x1][y1] == 'T') return dis;
      if (vis[x1][y1][x2][y2]) continue;
      vis[x1][y1][x2][y2] = true;
      int ni = -1;
      for (int i = 0; i < 4; i++) {
        int nx2 = x2 + d[i], ny2 = y2 + d[i + 1];
        if (0 <= nx2 && nx2 < m && 0 <= ny2 && ny2 < n && g[nx2][ny2] != '#' &&
            dist[x1][y1][nx2][ny2] > dis) {
          if (nx2 == x1 && ny2 == y1) {
            ni = i;
            continue;
          }
          dist[x1][y1][nx2][ny2] = dis;
          dq.push_front({x1, y1, nx2, ny2});
        }
      }
      // 如果人不在箱子旁边,则略过第二种转移的情况
      if (ni == -1) continue;
      int nx1 = x1 + d[ni], ny1 = y1 + d[ni + 1];
      if (0 <= nx1 && nx1 < m && 0 <= ny1 && ny1 < n && g[nx1][ny1] != '#' &&
          dist[nx1][ny1][x1][y1] > dis + 1) {
        dist[nx1][ny1][x1][y1] = dis + 1;
        dq.push_back({nx1, ny1, x1, y1});
      }
    }

    return -1;
  }
};

时空复杂度 O ( ( m n ) 2 ) O((mn)^2) O((mn)2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值