链接: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 =0 and new_y
C++:
class Solution {
public:
double knightProbability(int N, int K, int r, int c) {
vector>> dp(N,vector>(N,vector(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=0 && new_x=0 && new_y