您的位置:首页 > 其它

Knight Probability in Chessboard

2018-01-15 00:00 162 查看
问题:

On an
N
x
N
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.



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.

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.

Example:

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:

N
will be between 1 and 25.

K
will be between 0 and 100.

The knight always initially starts on the board.

解决:

【题意】

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

① 要求概率,我们必须要先分别求出分子和分母,其中分子是走完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

;
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

;
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]

;
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];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: