棋盤遊戲走完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];     } }

相關文章
相關標籤/搜索