一道有趣的动态规划题目
问题描述
给定一个 m x n 大小的矩阵,计算从左上角到右下角的路径数量(只允许向下或者向右移动),要求路径所经历的拐点数目不大于 k。
什么是拐点?如果我们本来沿着行移动,但是现在沿着列移动,则认为路径经过了一个拐点;或者本来沿着列移动,现在沿着行移动。拐点可能发生时有两种可能的情况:
在点 (i, j):
- 向右转: (i-1, j) -> (i, j) -> (i, j + 1)
- 向下转: (i, j-1) -> (i, j) -> (i + 1, j)
对于下图:
1 | 输入:m = 3,n = 3,k = 2 |
求解分析
这是一道典型的动态规划题目,可以列出转移方程的形式。
首先定义计算路径的函数:
countPaths(i,j,k)
:从 (0, 0) 到达 (i, j) 的路径的数量countPathsDir(i,j,k,0)
:沿着行方向到达 (i, j) 的路径数量。countPathsDir(i,j,k,1)
:沿着列方向到达 (i, j) 的路径数量。
countPathsDir
中的第四个参数表示方向。因此:countPaths(i,j,k) = countPathsDir(i,j,k,0) + countPathsDir(i,j,k,1)
countPathsDir
的值可以递归地定义为:
1 | // 如果当前方向是沿着行 |
编程实现
我们可以使用动态编程在多项式时间中解决这个问题。想法是使用 4 维表 dp[m][n][k][d]
其中 m 是行数,n 是列数,k 是剩余的拐点数目,d 是方向。
下面是基于动态编程的 C++ 实现。
1 |
|