1263. 推箱子

题目:
「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。

游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。

现在你将作为玩家参与游戏,按规则将箱子 ‘B’ 移动到目标位置 ‘T’ :

玩家用字符 ‘S’ 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
地板用字符 ‘.’ 表示,意味着可以自由行走。
墙用字符 ‘#’ 表示,意味着障碍物,不能通行。
箱子仅有一个,用字符 ‘B’ 表示。相应地,网格上有一个目标位置 ‘T’。
玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
玩家无法越过箱子。
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-moves-to-move-a-box-to-their-target-location
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意:
规则其实就跟我们小时候玩的那个手机游戏–推箱子是一样的。

思路:
这道题其实思路很简单,和走迷宫是一个道理的,当你把箱子和人看成一个整体的时候,就是走迷宫,那直接搜索就可以解决了。

而这道题的不同之处在于,还有个人的位置要考虑。也就是从人出发,向四个方向搜索,如果人移动之后的位置是墙,那就是不合法的,回到上个状态搜索;如果人移动之后的位置是箱子的位置,就说明是合法的,然后将箱子进行对应的移动,判断是否合法,合法的话就存到q1队列中。那还有一种情况是人移动之后的位置不是墙也不是箱子的位置,那就用能走到此位置的最小值来更新它。因为我们最后的答案就是dp【】【】数组,所以这个值不能忽略,仍然要赋值。

详细的讲解如下:
n 是地图的列数 , m 是地图的行数。
solve()函数是用来判断 x , y 的位置是否合法。
sx,sy是人的位置。
bx,by是箱子的位置。
dp【i】【j】表示人在 i 位置箱子在 j 位置的最小步数。

首先将dp初始化为999999,然后将人的初始位置赋值为0.

然后将初始位置放入队列。

首先第一层循环,队列不为空的话:
新开一个队列 q1 , 用来存放从 q 中拿出的位置向四个方向移动后的合法位置。

sx1,sy1是对头的人的位置,bx1,by1是对头的箱子的位置。

如果此时箱子的位置是终点,那说明这个位置已经到达终点,dp[s1][b1]就是答案。

不是终点的话,像四个方向探索:
sx2,sy2是sx1,sy1移动后的人的位置,bx2,by2是bx1,by1移动后的箱子的位置。

首先判断sx2,sy2是否合法,不合法的话就下一个方向,合法的话判断,sx2,sy2人的位置是否和箱子的位置bx1,by1重合,重合的话才是真正意义上的推动箱子,就将箱子向同一方向移动,如果移动后的箱子的位置bx2,by2也合法的话,那dp【s2】【b2】的步数就是dp【s1】【b1】的步数加一,并将s2,b2加到q1中,因为他是新的合法的位置。

q遍历完,将q1的值赋给q,然后接着遍历q。这里q1的意义在于,因为我们是两层遍历q的循环,如果不设置q1的话,会造成循环的次序错误。

代码:

class Solution {
public:
    int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
    int n , m;
    bool solve(vector<vector<char>>& g , int& x , int& y){
        if(x < 0 || y < 0 || x >= m || y >= n || g[x][y] == '#')
            return false;
        return true;
    }
    int minPushBox(vector<vector<char>>& grid) {
        m = grid.size(); 
        n = grid[0].size();
        int sx , sy , bx , by;
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(grid[i][j] == 'S'){
                    sx = i;
                    sy = j;
                }
                else if(grid[i][j] == 'B'){
                    bx = i;
                    by = j;
                }
            }
        }
        int dp[1010][1010];
        for(int i = 0 ; i < 1010 ; i++){
            for(int j = 0 ; j < 1010 ; j++){
                dp[i][j] = 9999999;
            }
        }
        queue<pair<int,int>> q;
        dp[sx*n + sy][bx*n + by] = 0;
        q.push({sx*n+sy , bx*n+by});
        while(!q.empty()){
            queue<pair<int , int>> q1;
            while(!q.empty()){
                auto [s1,b1] = q.front();
                q.pop();
                int sx1 = s1/n , sy1 = s1%n , bx1 = b1/n , by1 = b1%n;
                if(grid[bx1][by1] == 'T')
                    return dp[s1][b1];
                for(int i = 0 ; i < 4 ; i++){
                    int sx2 = sx1 + dir[i][0];
                    int sy2 = sy1 + dir[i][1];
                    int s2 = sx2*n+sy2;
                    if(!solve(grid , sx2 , sy2))
                        continue;
                    if(bx1 == sx2 && by1 == sy2){
                        int bx2 = bx1 + dir[i][0];
                        int by2 = by1 + dir[i][1];
                        int b2 = bx2*n + by2;
                        if(!solve(grid , bx2 , by2) || dp[s2][b2] <= dp[s1][b1]+1)
                            continue;
                        dp[s2][b2] = dp[s1][b1] + 1;
                        q1.push({s2 , b2});
                    }
                    else{
                        if(dp[s2][b1] <= dp[s1][b1])
                            continue;
                        dp[s2][b1] = dp[s1][b1];
                        q.push({s2 , b1});
                    }
                }
            }
            q.swap(q1);
        }
        return -1;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值