python123中棋盘放米_688. 马在棋盘上的概率(Python)

马在棋盘上的概率(Python)

题目

难度:★★★☆☆

类型:数组

方法:动态规划

力扣链接请移步本题传送门

更多力扣中等题的解决方案请移步力扣中等题目录

已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。

现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。

国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。

现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。

求移动结束后,“马” 仍留在棋盘上的概率。

示例:

输入: 3, 2, 0, 0

输出: 0.0625

解释:

输入的数据依次为 N, K, r, c

第 1 步时,有且只有 2 种走法令 “马” 可以留在棋盘上(跳到(1,2)或(2,1))。对于以上的两种情况,各自在第2步均有且只有2种走法令 “马” 仍然留在棋盘上。

所以 “马” 在结束后仍在棋盘上的概率为 0.0625。

注意:

N 的取值范围为 [1, 25]

K 的取值范围为 [0, 100]

开始时,“马” 总是位于棋盘上

解答

方法1:动态规划

【矩阵定义】:定义一个K+1xNxN维度的三维矩阵dp,其中任意一点(k_, r_, c_)表示马走k_步后落在点(r_, c_)处的概率。这里在K维度上增加一维用来表示初始状态也就是马走零步的状态。

【初始状态】

由于马的最初位置是(r,c),因此马走零步落在点(r,c)的概率为1,因此填充dp[0][r][c] = 1,其他位置填充零。

【递推公式】

对于当前位置(r_, c_),马可以由八个方向跳过来:directions= [(2, 1), (2, -1), (1, 2), (1, -2), (-2, 1), (-2, -1), (-1, 2), (-1, -2)],对于每一个位置,马也可以等概率的跳到以上八个方向中任意一个。每一步的概率取决于上一步,每一个点的概率取决于八个特定方向临近点,因此,递推公式为:

dp[k_][r_][c_] = sum([dp[k_-1][r_+dr][c_+dc]/8 for dr, dc in directions])

这里需要注意判断求解概率的点不要越过棋盘边界。

【最终结果】

最后,我们选择最后一步的概率网格,求取网格所有点的和,即为K步后马还在棋盘中的概率。

class Solution:

def knightProbability(self, N, K, r, c):

dp = [[[0 for _ in range(N)] for _ in range(N)] for _ in range(K+1)]

dp[0][r][c] = 1

directions = [(2, 1), (2, -1), (1, 2), (1, -2),

(-2, 1), (-2, -1), (-1, 2), (-1, -2)

]

for k_ in range(1, K+1):

print(dp[k_])

for r_ in range(N):

for c_ in range(N):

for dr, dc in directions:

if 0 <= r_+dr < N and 0 <= c_+dc < N:

dp[k_][r_][c_] += dp[k_-1][r_+dr][c_+dc] / 8

return sum([prob for row in dp[-1] for prob in row])

方法2:记忆化深度优先搜索

为了简化计算,我们使用字典记录已经出现过的概率值,即将上述的三维网格按照位置-概率进行对应,通过及时的查找避免重复的计算。

这里用深度优先搜索方式代替动态规划,其一般规则是:首先判断特殊情况,例如越界或记录已经存在于字典中。注意这里dfs函数的返回值代表的是以从点(r,c)出发,K步后马还在棋盘上的概率,而非落在(r,c)点的概率。

class Solution:

def knightProbability(self, N, K, r, c):

memory = dict()

directions = ((-1, -2), (-2, -1), (-2, 1), (-1, 2), (1, -2), (2, -1), (2, 1), (1, 2))

def dfs(K, r, c):

if not (0 <= r < N and 0 <= c < N):

return 0

if K == 0:

return 1

if (K, r, c) in memory:

return memory[(K, r, c)]

p = sum([dfs(K - 1, r + dr, c + dc) / 8.0 for dr, dc in directions])

memory.update({(K, r, c): p})

return p

return dfs(K, r, c)

如有疑问或建议,欢迎评论区留言~

有关更多力扣中等题的python解决方案,请移步力扣中等题解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值