算法第三章

1.1
状态定义:
设 dp[i][j] 表示从左上角 (0,0) 走到网格第 i 行第 j 列位置 (i,j) 时所需要的最小总费用。
设 m[i][j] 表示网格在第 i 行第 j 列方格本身所需的费用。
最优子结构性质与递归方程式:
要到达位置 (i,j),商人只能从它的正上方 (i-1,j) 向下走一步,或者从它的正左方 (i,j-1) 向右走一步到达。
因此,到达 (i,j) 的最小费用,等于到达其上方或左方这两个相邻方格中的最小费用,再加上当前方格本身的费用。
递归方程式:
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + m[i][j]

边界条件:

  1. 起点:dp[0][0] = m[0][0] (初始位置费用即为该格子的费用)。
  2. 第一行(只能一直向右走):当 i = 0 且 j > 0 时,dp[0][j] = dp[0][j-1] + m[0][j]。
  3. 第一列(只能一直向下走):当 j = 0 且 i > 0 时,dp[i][0] = dp[i-1][0] + m[i][0]

1.2
表的维度:代码中定义为 dp[105][105]
填表范围:行索引 i 从 0 到 N-1;列索引 j 从 0 到 N-1。
填表顺序:从上到下,从左到右(即外层循环遍历行 i,内层循环遍历列 j)。
(原因:计算 dp[i][j] 时,需要依赖它左边 dp[i][j-1] 和上边 dp[i-1][j] 的值,因此必须保证这两个方向的值已经计算完毕。)

1.3
时间复杂度:O(N^2)。
程序使用了两层嵌套的 for 循环遍历整个 N \times N 的网格,每次状态转移(取最小值并相加)的时间复杂度为 O(1),因此总时间复杂度为 O(N^2)。
空间复杂度:O(N^2)。
使用了一个二维数组 dp[N][N] 来存储中间状态,以及一个二维数组 m[N][N] 来存储输入的网格费用。因此空间复杂度为 O(N^2)

通过本次实践,我对动态规划有了以下几点深刻体会:

  1. 本质是“空间换时间”:通过数组(如 dp 表)记录已解决的子问题,避免重复计算,将复杂问题的时间复杂度从指数级降至多项式级(如本题的 O(N^2))。
  2. 核心是“状态与转移”:解题关键在于精准定义状态(dp[i][j] 代表什么)和推导状态转移方程。利用最优子结构,把大问题拆解为由相邻子问题构成的递推关系。
  3. 细节决定成败:边界条件(如第一行、第一列)的初始化和填表顺序至关重要。填表顺序必须严格遵循状态的依赖关系(如自顶向下、自左向右)。
  4. 全局最优思维:与只看局部的贪心算法不同,动态规划在每一步都权衡对比所有可能的子问题解(如本题取 min),从而保证最终得到的是全局最优解。
    原问题的最优值:表格的右下角元素,即 dp[N-1][N-1]
posted @ 2026-11-03 14:32  .7even  阅读(1)  评论(0)    收藏  举报