JAVA程序设计:猫和老鼠 II(LeetCode:1728)

一只猫和一只老鼠在玩一个叫做猫和老鼠的游戏。

它们所处的环境设定是一个 rows x cols 的方格 grid ,其中每个格子可能是一堵墙、一块地板、一位玩家(猫或者老鼠)或者食物。

玩家由字符 'C' (代表猫)和 'M' (代表老鼠)表示。
地板由字符 '.' 表示,玩家可以通过这个格子。
墙用字符 '#' 表示,玩家不能通过这个格子。
食物用字符 'F' 表示,玩家可以通过这个格子。
字符 'C' , 'M' 和 'F' 在 grid 中都只会出现一次。
猫和老鼠按照如下规则移动:

老鼠 先移动 ,然后两名玩家轮流移动。
每一次操作时,猫和老鼠可以跳到上下左右四个方向之一的格子,他们不能跳过墙也不能跳出 grid 。
catJump 和 mouseJump 是猫和老鼠分别跳一次能到达的最远距离,它们也可以跳小于最大距离的长度。
它们可以停留在原地。
老鼠可以跳跃过猫的位置。
游戏有 4 种方式会结束:

如果猫跟老鼠处在相同的位置,那么猫获胜。
如果猫先到达食物,那么猫获胜。
如果老鼠先到达食物,那么老鼠获胜。
如果老鼠不能在 1000 次操作以内到达食物,那么猫获胜。
给你 rows x cols 的矩阵 grid 和两个整数 catJump 和 mouseJump ,双方都采取最优策略,如果老鼠获胜,那么请你返回 true ,否则返回 false 。

 

示例 1:

输入:grid = ["####F","#C...","M...."], catJump = 1, mouseJump = 2
输出:true
解释:猫无法抓到老鼠,也没法比老鼠先到达食物。
示例 2:

输入:grid = ["M.C...F"], catJump = 1, mouseJump = 4
输出:true
示例 3:

输入:grid = ["M.C...F"], catJump = 1, mouseJump = 3
输出:false
示例 4:

输入:grid = ["C...#","...#F","....#","M...."], catJump = 2, mouseJump = 5
输出:false
示例 5:

输入:grid = [".M...","..#..","#..#.","C#.#.","...#F"], catJump = 3, mouseJump = 1
输出:true
 

提示:

rows == grid.length
cols = grid[i].length
1 <= rows, cols <= 8
grid[i][j] 只包含字符 'C' ,'M' ,'F' ,'.' 和 '#' 。
grid 中只包含一个 'C' ,'M' 和 'F' 。
1 <= catJump, mouseJump <= 8


思路:这道题和猫和老鼠I具有异曲同工之妙,虽然规则更复杂,但是解法确实如出一辙,我们仍然考虑起始的必胜态和必败态:

1⃣️当老鼠和猫在同一个位置时猫获胜

2⃣️当老鼠先到达食物位置时,老鼠获胜

3⃣️当猫先到达食物位置时,猫获胜

而我们额需要牢记的无非只有两点【摘自零神】:

1⃣️ 一个状态为「必胜态」,当且仅当其相邻状态中至少有一个「必败态」。因此,如果一个状态是「必败态」,那么其相邻的所有状态都是「必胜态」。因此我们可以从预先计算出的所有「必败态」开始进行广度优先搜索,它们相邻的所有状态都是「必胜态」;

2⃣️ 一个状态为「必败态」,当且仅当其相邻的所有状态都是「必胜态」。因此,如果一个状态是「必胜态」,那么我们可以将其相邻的所有状态的入度都减少 1。如果某个状态的入度减少到了0 并且它还没有被计算过,那么说明其相邻的所有状态都是「必胜态」,那么它就是「必败态」。

之后就是经典广搜版拓扑排序了。

class Solution {

    private int m, n;
    private char[][] grid;
    private int[][][][][] f;
    private int[][][][][] ingree;
    private int[] dx = new int[]{1, -1, 0, 0};
    private int[] dy = new int[]{0, 0, 1, -1};

    class state {
        int x, y, xx, yy, id;

        public state(int x, int y, int xx, int yy, int id) {
            this.x = x;
            this.y = y;
            this.xx = xx;
            this.yy = yy;
            this.id = id;
        }
    }

    public boolean canMouseWin(String[] grid, int catJump, int mouseJump) {
        m = grid.length;
        n = grid[0].length();
        this.grid = new char[m][n];
        f = new int[m][n][m][n][2];
        ingree = new int[m][n][m][n][2];
        int cx = 0, cy = 0, mx = 0, my = 0, fx = 0, fy = 0;

        for (int i = 0; i < m; i++) {
            this.grid[i] = grid[i].toCharArray();
            for (int j = 0; j < n; j++) {
                char c = this.grid[i][j];
                if (c == 'M') {
                    mx = i;
                    my = j;
                } else if (c == 'C') {
                    cx = i;
                    cy = j;
                } else if (c == 'F') {
                    fx = i;
                    fy = j;
                }
            }
        }

        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                if (this.grid[i][j] == '#')
                    continue;
                for (int k = 0; k < m; k++)
                    for (int h = 0; h < n; h++) {
                        if (this.grid[k][h] == '#')
                            continue;
                        ingree[i][j][k][h][0] = getNeighbors(k, h, mouseJump).size();
                        ingree[i][j][k][h][1] = getNeighbors(i, j, catJump).size();
                    }
            }

        Queue<state> q = new LinkedList<>();

        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                if (this.grid[i][j] == '#' || this.grid[i][j] == 'F')
                    continue;
                f[i][j][i][j][0] = -1;
                f[i][j][i][j][1] = 1;
                q.add(new state(i, j, i, j, 0));
                q.add(new state(i, j, i, j, 1));
            }

        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                if (this.grid[i][j] == '#' || this.grid[i][j] == 'F')
                    continue;
                f[fx][fy][i][j][0] = -1;
                f[i][j][fx][fy][1] = -1;
                q.add(new state(fx, fy, i, j, 0));
                q.add(new state(i, j, fx, fy, 1));
            }

        while (!q.isEmpty()) {
            state now = q.poll();
            if (now.id == 1) {
                List<int[]> nei = getNeighbors(now.xx, now.yy, mouseJump);
                for (int[] nxt : nei) {
                    int x = nxt[0], y = nxt[1];
                    if (f[now.x][now.y][x][y][0] != 0)
                        continue;
                    if (f[now.x][now.y][now.xx][now.yy][1] == -1) {
                        f[now.x][now.y][x][y][0] = 1;
                        q.add(new state(now.x, now.y, x, y, 0));
                    } else {
                        ingree[now.x][now.y][x][y][0]--;
                        if (ingree[now.x][now.y][x][y][0] == 0) {
                            f[now.x][now.y][x][y][0] = -1;
                            q.add(new state(now.x, now.y, x, y, 0));
                        }
                    }
                }
            } else {
                List<int[]> nei = getNeighbors(now.x, now.y, catJump);
                for (int[] nxt : nei) {
                    int x = nxt[0], y = nxt[1];
                    if (f[x][y][now.xx][now.yy][1] != 0)
                        continue;
                    if (f[now.x][now.y][now.xx][now.yy][0] == -1) {
                        f[x][y][now.xx][now.yy][1] = 1;
                        q.add(new state(x, y, now.xx, now.yy, 1));
                    } else {
                        ingree[x][y][now.xx][now.yy][1]--;
                        if (ingree[x][y][now.xx][now.yy][1] == 0) {
                            f[x][y][now.xx][now.yy][1] = -1;
                            q.add(new state(x, y, now.xx, now.yy, 1));
                        }
                    }
                }
            }
        }
        return f[cx][cy][mx][my][0] == 1;
    }

    private List<int[]> getNeighbors(int x, int y, int jump) {
        List<int[]> res = new ArrayList<>();
        res.add(new int[]{x, y});
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= jump; j++) {
                int xx = x + j * dx[i];
                int yy = y + j * dy[i];
                if (xx < 0 || xx >= m || yy < 0 || yy >= n)
                    continue;
                if (grid[xx][yy] == '#')
                    break;
                res.add(new int[]{xx, yy});
            }
        }
        return res;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值