棋盘游戏走完k步还能留在棋盘上的几率

Knight Probability in Chessboard

问题:dom

On an NN chessboard, a knight starts at the r-th row and c-th column and attempts to make exactly K moves. The rows and columns are 0 indexed, so the top-left square is (0, 0), and the bottom-right square is (N-1, N-1).函数

A chess knight has 8 possible moves it can make, as illustrated below. Each move is two squares in a cardinal direction, then one square in an orthogonal direction.spa

Each time the knight is to move, it chooses one of eight possible moves uniformly at random (even if the piece would go off the chessboard) and moves there..net

The knight continues moving until it has made exactly K moves or has moved off the chessboard. Return the probability that the knight remains on the board after it has stopped moving.code

Example:orm

Input: 3, 2, 0, 0
Output: 0.0625
Explanation: There are two moves (to (1,2), (2,1)) that will keep the knight on the board.
From each of those positions, there are also two moves that will keep the knight on the board.
The total probability the knight stays on the board is 0.0625.

Note:blog

  • N will be between 1 and 25.
  • K will be between 0 and 100.
  • The knight always initially starts on the board.

解决:递归

【题意】rem

给定一个大小为NxN国际象棋棋盘,上面有个骑士,能走‘日’字,给定一个起始位置,而后说容许咱们走K步,问走完K步以后还能留在棋盘上的几率是多少。get

①  要求几率,咱们必需要先分别求出分子和分母,其中分子是走完K步还在棋盘上的走法,分母是没有限制条件的总共的走法

每步走有8种跳法,那么K步就是8的K次方种了,分母为8^k。

对于分子,并不须要骑士的起始位置,而是把棋盘上全部位置上通过K步还留在棋盘上的走法总和都算出来,那么最后直接返回须要的值便可。这须要使用动态规(与Out of Boundary Paths相似):

  • dp[i][j]表示在棋盘(i, j)位置上走完当前步还留在棋盘上的走法总和,初始化为1。

  class Solution { //18ms
    public double knightProbability(int N, int K, int r, int c) {
        if (K == 0) return 1;
        double[][] dp = new double[N][N];
        for (int i = 0;i < N;i ++){
            Arrays.fill(dp[i],1.0);
        }
        int[][] dirs = {{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};
        for (int m = 0;m < K;m ++){
            double[][] tmp = new double[N][N];
            for (int i = 0;i < N;i ++){
                for (int j = 0;j < N;j ++){
                    for (int[] dir : dirs){
                        int x = i + dir[0];
                        int y = j + dir[1];
                        if (x < 0 || x >= N || y < 0 || y >= N) continue;
                        tmp[i][j] += dp[x][y];
                    }
                }
            }
            dp = tmp;
        }
        return dp[r][c] / Math.pow(8,K);
    }
}

② dfs + dp,dp[k][r][c]表示从坐标(r,c)开始走k步,还在棋盘上的走法,初始化为0。

递归函数中,若是k为0了,说明已经走了k步,返回 1。若是dp[k][r][c]不为0,说明这种状况以前已经计算过,直接返回。而后遍历8种走法,计算新的位置,若是不在棋盘上就跳过;而后更新dp[k][r][c],使其加上对新位置调用递归的返回值,注意此时带入k-1和新的位置,退出循环后返回dp[k][r][c]便可。

class Solution { //13ms     public double knightProbability(int N, int K, int r, int c) {         double[][][] dp = new double[K + 1][N][N];         return dfs(N,K,r,c,dp) / Math.pow(8,K);     }     int[][] dirs = {{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};     public double dfs(int N,int K,int r,int c,double[][][] dp){         if (K == 0) return 1.0;         if (dp[K][r][c] != 0.0) return dp[K][r][c];         for (int[] dir : dirs){             int x = r + dir[0];             int y = c + dir[1];             if (x < 0 || x >= N || y < 0 || y >= N) continue;             dp[K][r][c] += dfs(N,K - 1,x,y,dp);         }         return dp[K][r][c];     } }

相关文章
相关标签/搜索