leetcode-骑士在棋盘上的概率

155 阅读2分钟

「这是我参与2022首次更文挑战的第30天,活动详情查看:2022首次更文挑战」。

题目

在一个 n x n 的国际象棋棋盘上,一个骑士从单元格 (row, column) 开始,并尝试进行 k 次移动。行和列是 从 0 开始 的,所以左上单元格是 (0,0) ,右下单元格是 (n - 1, n - 1) 。
象棋骑士有8种可能的走法,如下图所示。每次移动在基本方向上是两个单元格,然后在正交方向上是一个单元格。
knight.png

每次骑士要移动时,它都会随机从8种可能的移动中选择一种(即使棋子会离开棋盘),然后移动到那里。
骑士继续移动,直到它走了 k 步或离开了棋盘。
返回 骑士在棋盘停止移动后仍留在棋盘上的概率 。

示例 1:
输入:n = 3, k = 2, row = 0, column = 0
输出:0.0625
解释:有两步(到(1,2),(2,1))可以让骑士留在棋盘上。
在每一个位置上,也有两种移动可以让骑士留在棋盘上。
骑士留在棋盘上的总概率是0.0625。

示例 2:
输入:n = 1, k = 0, row = 0, column = 0
输出:1.00000

思路

这题可以按照动态规划的套路来做。 定义一个三维数组dp,dp[step][i][j]代表初始在(i,j)位置的棋子,经过step步后,依然留在棋盘上的概率。由于马走日字形,一共有8中可能,定义offsets数组,表述8种可能的坐标变化,那么状态转移方程可以总结为

dp[step][i][j] = sum(dp[step-1][i+offset[0]][j+offset[1]])

对于初始值,即step=0的情况,只要原始位置在棋盘上,就肯定在棋盘上,所以可以初始dp[0][i][j] = 1。

另外有个疑问:原题中有“0 <= row, column <= n”,感觉这里等号写错了,不然我下面的代码没考虑row, column = n 的情况,应该AC不过去。

Java版本代码

class Solution {
    public double knightProbability(int n, int k, int row, int column) {
        int[][] offsets = new int[][]{{1,2}, {1,-2}, {-1,2}, {-1,-2}, {2,1}, {2,-1}, {-2,1}, {-2,-1}};
        double[][][] dp = new double[k+1][n][n];
        for (int step = 0; step <= k; step++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (step == 0) {
                        dp[step][i][j] = 1;
                    } else {
                        for (int[] offset : offsets) {
                            int x = i + offset[0];
                            int y = j + offset[1];
                            if (x>=0 && x<n && y>=0 && y<n) {
                                dp[step][i][j] += dp[step-1][x][y] / 8;
                            }
                        }   
                    }
                }
            }
        }
        return dp[k][row][column];
    }
}