Cynthia1912

导航

动态规划

最低通行费 动态规划实践报告

1.1 递归方程、定义、边界条件

状态定义

设 (dp[i][j]):走到网格第 i 行、第 j 列方格时,所需的最小通行总费用。
(a[i][j]):方格 ((i,j)) 本身的费用。

递归方程(状态转移方程)

(dp[i][j] = a[i][j] + \min
\begin{cases}
dp[i-1][j] \quad \text{从上方格子走下来}\
dp[i][j-1] \quad \text{从左方格子走过来}
\end{cases})>

含义:到达 ((i,j)) 的最小费用 = 当前格子费用 + 上方、左边两个方案里费用更小的那一个。

边界条件

  1. 起点:(dp[1][1] = a[1][1]),左上角就是起点,费用就是格子本身费用。
  2. 第一行((i=1,j>1)):上面没有格子,只能从左边过来

(dp[1][j] = dp[1][j-1] + a[1][j])
3. 第一列((j=1,i>1)):左边没有格子,只能从上面下来

(dp[i][1] = dp[i-1][1] + a[i][1])

最优子结构说明:
到达 ((i,j)) 的最优路径,它到达前一步(上方或者左方)的路径一定也是最优的。如果前一步有更便宜的走法,替换之后就能得到更优解,矛盾。满足最优子结构;同时子问题会重复使用,适合动态规划。


1.2 填表:维度、填表范围、填表顺序、答案位置

  1. 表的维度:二维数组 (dp[N+1][N+1])(下标从 1 开始,方便处理边界,避开 0 下标判断),和网格大小一致。
  2. 填表范围:i 从 (1\sim N),j 从 (1\sim N)
  3. 填表顺序:
    • 先填边界:第一行从左往右;第一列从上往下
    • 然后按行优先顺序(从上到下,每行内部从左到右)填充内部格子。
      理由:计算 (dp[i][j]) 需要 (dp[i-1][j])(上一行,已经算好)、(dp[i][j-1])(本行左边,已经算好)。
  4. 原问题最优值:(\boldsymbol{dp[N][N]}),也就是右下角单元格的值。

样例 N=5,最终答案就是 (dp[5][5]=109),和题目输出一致。


1.3 时间复杂度 & 空间复杂度

  • 时间复杂度 (O(N^2))
    一共 (N\times N) 个状态,每个状态只做一次 min 比较和加法,常数时间。
  • 空间复杂度 (O(N^2))
    开了大小为 (N\times N) 的 dp 二维数组;

对动态规划算法的理解和体会

动态规划核心是拆分问题、利用最优子结构、记录子问题答案避免重复计算,和暴力搜索完全不一样:

  1. 暴力 DFS 会枚举所有路径,大量重复计算相同位置的路径开销,N 稍大就超时;DP 把每个位置的最优解存下来,每个子问题只算一次。
  2. 使用 DP 有两个前提:最优子结构 + 无后效性。
    • 最优子结构:全局最优由局部最优构成;
    • 无后效性:(dp[i][j]) 的值一旦确定,后面的计算只依赖这个值,不再关心它是怎么走过来的。
  3. 这道题很有代表性:题目给的时间限制不是多余条件,它直接限制移动方向,把 “四向搜索” 简化成 “只能右、下”,降低难度。审题时要挖掘这种隐藏约束,才能写出正确转移方程。
  4. DP 做题套路一般固定:
    ① 定义 dp 状态;② 找状态转移方程;③ 确定边界;④ 确定填表顺序;⑤ 找到最终答案位置。
  5. 同时也要注意:DP 不是万能的,如果不满足最优子结构就不能用;有时候还可以做空间优化,压缩二维 dp 到一维,节省内存。

posted on 2026-11-02 16:43  Cynthia1912  阅读(2)  评论(0)    收藏  举报