📌  相关文章
📜  到达棋盘末端的预期移动次数|矩阵求幂(1)

📅  最后修改于: 2023-12-03 14:50:21.624000             🧑  作者: Mango

初识问题

在一个 $n$ 行 $m$ 列的棋盘游戏中,我们将一个棋子放在左上角 $(1, 1)$ 的位置上,现在需要将棋子移动到右下角 $(n, m)$ 处。

每一步棋子可以向下或向右移动一格,直到到达终点。现在,我们假设每一格向下或向右移动的概率都是相等的,求到达终点的预期移动次数。

矩阵求幂

观察到这是一种标准的概率问题,我们可以使用矩阵乘法来解决。需要注意的是,矩阵的幂次运算在计算机科学中是一种常见的操作,可以使用快速幂算法来进行优化。

首先,我们定义一个 $n \times m$ 的矩阵 $A$,其中 $a_{i, j}$ 表示从 $(i, j)$ 这个位置开始到达终点 $(n, m)$ 的预期移动次数。根据题意,我们可以得到:

$$ \begin{aligned} a_{i,j} &= 0, i > n \text{ 或 } j > m \ a_{n,m} &= 0 \ a_{i,j} &= \frac{1}{2} (a_{i+1,j} + a_{i,j+1}) + 1 \end{aligned} $$

用矩阵乘法表示上述过程,即:

$$ A = \frac{1}{2} \begin{bmatrix} 0 & E_{n-1 \times m} \ E_{n \times m-1} & 0 \end{bmatrix} + I_{n \times m} $$

其中,$E_{n \times m}$ 表示 $n \times m$ 的单位矩阵,$I_{n \times m}$ 表示 $n \times m$ 的全一矩阵。由于矩阵乘法的结合律,我们可以使用矩阵快速幂算法来计算 $A^k$,从而得到到达终点的预期移动次数。

代码实现

import numpy as np

def expected_moves(n: int, m: int) -> float:
    N = n * m
    A = np.zeros((N, N))
    for i in range(n):
        for j in range(m):
            k = i * m + j
            if i == j == 0:
                A[k][k] = 1
            elif i == n-1 and j == m-1:
                A[k][k] = 0
            elif i == n-1:
                A[k][k+1] = 1/2
            elif j == m-1:
                A[k][k+m] = 1/2
            else:
                A[k][k+1] = 1/2
                A[k][k+m] = 1/2
    A = A @ 0.5 + np.eye(N)
    A_k = np.linalg.matrix_power(A, N)
    return A_k[0][N-1]

以上代码实现了预期移动次数的计算,其中 $N = n \times m$。使用numpy库中的linalg.matrix_power函数来进行矩阵快速幂计算,快速算出 $A^k$。最后返回矩阵的左上角元素来得到所需结果。

总结

本文使用矩阵乘法和快速幂算法解决了到达棋盘末端的预期移动次数问题。对于初学者,矩阵和矩阵幂次的概念可能有些抽象,但只要理解了背后的运算理念,加上一些常见的前置知识,理解起来还是十分容易的。