【每日一题Day200】LC1263推箱子 | 01-BFS

简介: 【每日一题Day200】LC1263推箱子 | 01-BFS

推箱子【LC1263】

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

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

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

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

返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1

新知识++

  • 思路

简单情况:不需要玩家推动箱子,那么就是箱子位置到目标位置的最小移动次数,可以使用BFS搜索最短路径

本题需要玩家去推动箱子,因此需要记录玩家的位置,枚举玩家的移动方向,如果移动位置合法,那么判断是否移动了箱子以及移动后的箱子位置是否合法,如果玩家移动时推动了箱子,那么推动次数加1。【如果玩家移动后的位置等于箱子位置,那么表示推动了箱子】。当箱子到达了目标位置,就得到了最小推动次数。

在BFS时,需要记录三元组[ 箱子位置 , 玩家位置 , 推动次数 ] [箱子位置,玩家位置,推动次数][箱子位置,玩家位置,推动次数],由于玩家在移动过程中,推动箱子的次数不一定增加,因此需要使用双端队列进行BFS(0-1BFS),如果移动次数未增加那么将三元组放入队列的顶部,如果移动次数增加那么将三元组放入队列的末尾,保证先搜索小状态,后搜索大状态。

同时,为了避免重复访问,记录每种情况的访问状态

实现

class Solution {
    private int m;
    private int n;
    private char[][] grid;
    public int minPushBox(char[][] grid) {
        m = grid.length;
        n = grid[0].length;
        this.grid = grid;
        int si = 0, sj = 0, bi = 0, bj = 0;
        // 找到玩家、箱子起始位置以及箱子目标位置
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] == 'S') {
                    si = i;
                    sj = j;
                } else if (grid[i][j] == 'B') {
                    bi = i;
                    bj = j;
                }
            }
        }
        int[] dirs = {-1, 0, 1, 0, -1};
        Deque<int[]> q = new ArrayDeque<>();
        boolean[][] vis = new boolean[m * n][m * n];
        // 将初始三元组入队
        q.offer(new int[] {f(si, sj), f(bi, bj), 0});
        vis[f(si, sj)][f(bi, bj)] = true;
        while (!q.isEmpty()) {
            var p = q.poll();
            int d = p[2];
            bi = p[1] / n;
            bj = p[1] % n;
            // 箱子是否已经到目标位置
            if (grid[bi][bj] == 'T') {
                return d;
            }
            si = p[0] / n;
            sj = p[0] % n;
            // 玩家移动
            for (int k = 0; k < 4; ++k) {
                int sx = si + dirs[k], sy = sj + dirs[k + 1];
                if (!check(sx, sy)) {// 非法
                    continue;
                }
                if (sx == bi && sy == bj) {
                    int bx = bi + dirs[k], by = bj + dirs[k + 1];
                    if (!check(bx, by) || vis[f(sx, sy)][f(bx, by)]) {// 非法或者已经访问过
                        continue;
                    }
                    vis[f(sx, sy)][f(bx, by)] = true;
                    q.offer(new int[] {f(sx, sy), f(bx, by), d + 1});// 箱子移动次数加1
                } else if (!vis[f(sx, sy)][f(bi, bj)]) {// 没有访问过
                    vis[f(sx, sy)][f(bi, bj)] = true;
                    q.offerFirst(new int[] {f(sx, sy), f(bi, bj), d});// 更新玩家位置
                }
            }
        }
        return -1;
    }
  // 将二维坐标转化为一维坐标
    private int f(int i, int j) {
        return i * n + j;
    }
  // 检查该位置是否越界或者是墙壁
    private boolean check(int i, int j) {
        return i >= 0 && i < m && j >= 0 && j < n && grid[i][j] != '#';
    }
}
作者:ylb
链接:https://leetcode.cn/problems/minimum-moves-to-move-a-box-to-their-target-location/solutions/2261099/python3javacgotypescript-yi-ti-yi-jie-sh-xgcz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

image.png

目录
相关文章
|
6月前
【每日一题Day366】LC2103环和杆 | 状态压缩
【每日一题Day366】LC2103环和杆 | 状态压缩
48 0
|
6月前
【每日一题Day114】LC1223 掷骰子模拟 | 记忆化搜索+dp
【每日一题Day114】LC1223 掷骰子模拟 | 记忆化搜索+dp
54 0
|
6月前
【每日一题Day328】LC198打家劫舍 | 动态规划
【每日一题Day328】LC198打家劫舍 | 动态规划
52 0
|
6月前
【每日一题Day329】LC213打家劫舍Ⅱ | 动态规划
【每日一题Day329】LC213打家劫舍Ⅱ | 动态规划
38 0
|
6月前
【每日一题Day330】LC337打家劫舍Ⅲ | 动态规划
【每日一题Day330】LC337打家劫舍Ⅲ | 动态规划
35 0
|
6月前
|
存储 人工智能 BI
【每日一题Day216】LC1377 T 秒后青蛙的位置 | BFS DFS
【每日一题Day216】LC1377 T 秒后青蛙的位置 | BFS DFS
52 0
|
6月前
|
存储 算法
【每日一题Day310】LC1654到家的最少跳跃次数 | BFS
【每日一题Day310】LC1654到家的最少跳跃次数 | BFS
45 0
|
6月前
|
人工智能 BI
【每日一题Day324】LC1462课程表 IV | BFS 拓扑排序 Floyd
【每日一题Day324】LC1462课程表 IV | BFS 拓扑排序 Floyd
30 0
|
6月前
【每日一题Day126】LC1140石子游戏Ⅱ | 博弈dp 记忆化搜索
【每日一题Day126】LC1140石子游戏Ⅱ | 博弈dp 记忆化搜索
47 0
|
6月前
|
计算机视觉
【每日一题Day231】LC1240铺瓷砖 | 暴力回溯
【每日一题Day231】LC1240铺瓷砖 | 暴力回溯
55 0