[Leetcode]688.Knight Probability in Chessboard

链接:LeetCode688

已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。 
现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。 
如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。
现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。
求移动结束后,“马” 仍留在棋盘上的概率。

相关标签:动态规划

这并不是一道常规的动态规划题。但是如果想到动态规划来解,其转移方程也是不难想的。
首先创建一个三维数组\(dp[i][j][k]\),其中\(dp[i][j][k]\)表示棋盘位置为\(i\)\(j\)列的旗子经过\(k\)步后在棋盘上的概率。每一步,棋子共有八种走法,创建一个二维数组,保存这八个走法,每次循环这八步。对于某个点的八个走法中的任意一个,将该点的位置加上八个走法中的值,得到另外一个位置,用1/8 乘于另外位置上一步得到的棋子位于棋盘上的概率。

至于为什么是\(dp[i][j][k]\)呢?为什么我们要将走的步数放在最外面,这也不难想。我们走k步的状态是由走了k-1步时的状态得到的,所以我们想得到在位置\((i,j)\)上概率,肯定需要走了k-1步时的概率,所以要将k放在最外层进行遍历。

其代码如下:

python:

class Solution:
    def knightProbability(self, N: int, K: int, r: int, c: int) -> float:
        dp = [[[0 for _ in range(K+1)] for _ in range(N)] for _ in range(N)]
        for k in range(K+1):
            for i in range(N):
                for j in range(N):
                    if k==0:
                        dp[i][j][k] = 1
                    else:
                        for dx,dy in zip([-2,-2,-1,-1,1,1,2,2],[-1,1,-2,2,-2,2,-1,1]):
                            new_x = i+dx
                            new_y = j+dy
                            if new_x >=0 and new_x <N and new_y >=0 and new_y<N:
                                dp[i][j][k] += 1/8*dp[new_x][new_y][k-1]

        return dp[r][c][K]

C++:

class Solution {
public:
    double knightProbability(int N, int K, int r, int c) {
        vector<vector<vector<double>>> dp(N,vector<vector<double>>(N,vector<double>(K+1,0)));
        int direction[][2] = {{-1, -2}, {1, -2}, {-1, 2}, {1, 2}, {-2, -1}, {-2, 1}, {2, -1}, {2, 1}};
        for(int k=0;k<K+1;++k){
            for(int i=0;i<N;++i){
                for(int j =0;j<N;++j){
                    if(k==0){
                        dp[i][j][k] = 1.0;
                        continue;
                    }
                    for(int l=0;l<8;++l){
                        int dx=direction[l][0],dy=direction[l][1];
                        int new_x = i+dx,new_y=j+dy;
                        if(new_x>=0 && new_x<N && new_y>=0 && new_y<N)
                            dp[i][j][k] += 1.0/8.0*dp[new_x][new_y][k-1];
                    }
                }
            }
        }
        return dp[r][c][K];
    }
};
posted @ 2020-02-07 16:57  Jamest  阅读(175)  评论(0编辑  收藏  举报