动态规划
最低通行费 动态规划实践报告
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)) 的最小费用 = 当前格子费用 + 上方、左边两个方案里费用更小的那一个。
边界条件
- 起点:(dp[1][1] = a[1][1]),左上角就是起点,费用就是格子本身费用。
- 第一行((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 填表:维度、填表范围、填表顺序、答案位置
- 表的维度:二维数组 (dp[N+1][N+1])(下标从 1 开始,方便处理边界,避开 0 下标判断),和网格大小一致。
- 填表范围:i 从 (1\sim N),j 从 (1\sim N)
- 填表顺序:
- 先填边界:第一行从左往右;第一列从上往下
- 然后按行优先顺序(从上到下,每行内部从左到右)填充内部格子。
理由:计算 (dp[i][j]) 需要 (dp[i-1][j])(上一行,已经算好)、(dp[i][j-1])(本行左边,已经算好)。
- 原问题最优值:(\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 二维数组;
对动态规划算法的理解和体会
动态规划核心是拆分问题、利用最优子结构、记录子问题答案避免重复计算,和暴力搜索完全不一样:
- 暴力 DFS 会枚举所有路径,大量重复计算相同位置的路径开销,N 稍大就超时;DP 把每个位置的最优解存下来,每个子问题只算一次。
- 使用 DP 有两个前提:最优子结构 + 无后效性。
- 最优子结构:全局最优由局部最优构成;
- 无后效性:(dp[i][j]) 的值一旦确定,后面的计算只依赖这个值,不再关心它是怎么走过来的。
- 这道题很有代表性:题目给的时间限制不是多余条件,它直接限制移动方向,把 “四向搜索” 简化成 “只能右、下”,降低难度。审题时要挖掘这种隐藏约束,才能写出正确转移方程。
- DP 做题套路一般固定:
① 定义 dp 状态;② 找状态转移方程;③ 确定边界;④ 确定填表顺序;⑤ 找到最终答案位置。 - 同时也要注意:DP 不是万能的,如果不满足最优子结构就不能用;有时候还可以做空间优化,压缩二维 dp 到一维,节省内存。
posted on 2026-11-02 16:43 Cynthia1912 阅读(2) 评论(0) 收藏 举报
浙公网安备 33010602011771号