路径类 DP 是线性 DP 的一种变体,核心在于在 n × m 的矩阵中设定行走规则,求解从起点到终点的路径数、最小或最大路径和等问题。入门阶段常接触的《数字三角形》其实也属于这一范畴。下面通过三道经典题目来梳理这类问题的解题思路。
矩阵的最小路径和
题目描述 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。每次只能向下或者向右移动一步。
思路解析
- 状态表示
定义
dp[i][j]为从起点(1, 1)走到格子(i, j)时,所有方案下的最小路径和。 - 状态转移
考虑到达当前格子的最后一步,只能来自上方或左方。因此,
dp[i][j]的值取决于dp[i-1][j]和dp[i][j-1]中的较小值加上当前格子的数值。 方程如下:dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] - 初始化
由于填表时需要访问左边和上边的格子,我们需要处理边界情况。为了方便,通常将第 0 行和第 0 列初始化为无穷大,这样在取最小值时永远不会选中它们。同时,起点
dp[1][1]应初始化为网格起点的值。注意在循环中跳过起点,避免重复计算导致错误。 - 填表顺序 从上往下,从左往右。
- 结果输出
最终答案存储在
dp[n][m]中。
代码实现
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
int n, m;
int a[N][N], dp[N][N];
int main() {
// 处理输入
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
// 初始化:第 0 行和第 0 列设为无穷大
memset(dp, 0x3f3f3f3f, sizeof(dp));
dp[1][1] = a[][];
( i = ; i <= n; i++) {
( j = ; j <= m; j++) {
(i == && j == ) ;
dp[i][j] = (dp[i - ][j], dp[i][j - ]) + a[i][j];
}
}
cout << dp[n][m] << endl;
;
}


