📅  最后修改于: 2023-12-03 14:51:30.720000             🧑  作者: Mango
在矩阵中从原点开始到达 (M, N) 而不访问 (X, Y) 的方法数,是一个经典的动态规划问题。
题目描述:有一个 M * N 的矩阵,从矩阵的左上角 (0, 0) 出发,到达矩阵的右下角 (M, N)。在走的过程中不能访问到 (X, Y) 这个点。求有多少种不同的走法。
例如,下图是一个 5 * 5 的矩阵,从左上角 (0, 0) 到右下角 (5, 5),不能经过 (2, 2) 的所有路径。
首先,我们可以使用深度优先搜索(DFS)来解决这个问题。我们从起点开始,依次遍历所有能够走的方向。如果遇到了要求禁止经过的点,我们直接跳过该方向。如果我们到达了终点,就将计数器加一。
这种方法可以解决问题,但是时间复杂度太高了,无法通过较大的测试数据,因此我们要寻找更加高效的解决方法。
由于这是一个经典的动态规划问题,我们可以使用动态规划的思想来解决它。我们从起点开始,依次计算到达每个位置的路径数。当我们到达终点时,就可以得到答案。
我们可以使用一个二维数组 dp[i][j] 来记录从起点到达位置 (i, j) 的路径数。我们可以将这个数组初始化为 0,然后依次计算每个位置的路径数,最终得到 dp[M][N] 就是答案。
下面是动态规划的具体实现:
首先,我们将 dp[0][0] 设置为 1,表示从起点出发到达起点的路径数为 1。
然后,我们依次计算每个位置的路径数。具体计算方法如下:
如果当前位置是要求禁止经过的点,那么 dp[i][j] 的值就是 0,因为从该点出发无法到达终点。
否则,我们可以从其左边和上边的格子出发到达当前格子。因此,dp[i][j] = dp[i-1][j] + dp[i][j-1]。
上面的算法还有一个问题,就是如果要求禁止经过的点在路径上怎么办?例如,当 M = N = 2,(X, Y) = (1, 1) 时,这个问题就会出现。
为了避免这个问题,我们可以将 dp 数组分为两个部分,分别计算从起点到达 (X, Y-1) 和从 (X+1, Y) 到达终点的路径数。然后将这两个路径数相乘,就是最终的答案。
下面是动态规划的 Python 代码实现:
def countPaths(M, N, X, Y):
# 初始化 dp 数组
dp1 = [[0] * (Y+1) for _ in range(X+1)]
dp2 = [[0] * (N-Y) for _ in range(M-X)]
dp1[0][0] = 1
# 计算 dp1 数组
for i in range(0, X+1):
for j in range(0, Y+1):
if i == 0 and j == 0:
continue
if i == X and j == Y:
continue
if i > 0:
dp1[i][j] += dp1[i-1][j]
if j > 0:
dp1[i][j] += dp1[i][j-1]
# 计算 dp2 数组
for i in range(M-X):
for j in range(N-Y):
if i == 0 and j == 0:
continue
if i == M-X-1 and j == N-Y-1:
continue
if i > 0:
dp2[i][j] += dp2[i-1][j]
if j > 0:
dp2[i][j] += dp2[i][j-1]
# 计算答案
ans = dp1[X][Y-1] * dp2[M-X-1][N-Y-1] + \
dp1[X-1][Y] * dp2[M-X][N-Y-1] + \
dp1[X][Y-1] * dp2[M-X-1][N-Y] + \
dp1[X-1][Y] * dp2[M-X][N-Y]
return ans
下面是一些测试样例:
M = 5
N = 5
X = 2
Y = 2
ans = countPaths(M, N, X, Y)
print(ans) # 58
M = 2
N = 2
X = 1
Y = 1
ans = countPaths(M, N, X, Y)
print(ans) # 1
M = 1
N = 1
X = 0
Y = 0
ans = countPaths(M, N, X, Y)
print(ans) # 0
本题展示了一个经典的动态规划问题,通过思考可以想出一种高效的解决方法。在实现时,需要注意一些细节,例如如何处理要求禁止经过的点在路径上的情况。