芋泥奶酪包

导航

以最低通行费问题分析动态规划思想

一、实践报告
1.1 最优子结构性质、递归方程与边界条件
状态定义:dp[i][j]:从起点(1,1)走到位置(i,j)的最小通行总费用。

递归状态转移方程:dp[i][j] = min(dp[i-1][j],dp[i][j-1])+price[i][j])
含义:到达(i,j)只能从上方(i-1,j)向下走,或者从左侧(i,j-1)向右走。取两条路径中费用更小的值,再加上当前格子本身的费用。

边界条件

  1. 起点:dp[1][1] = price[1][1],起点的总费用就是当前格子费用。
  2. 第一行(i=1,j>1):无法从上方到达,只能一直向右走
    dp[1][j] = dp[1][j-1] + price[1][j]
  3. 第一列(j=1,i>1):无法从左侧到达,只能一直向下走
    dp[i][1] = dp[i-1][1] + price[i][1]

最优子结构说明
从起点到(i,j)的最优路径,它通往前驱点(i-1,j)或者(i,j-1)的子路径,一定也是对应子问题的最优解。
假设子路径存在一条费用更低的路线,用它替换原有子路径后,整体路径费用会更小,和原路径是最优解矛盾。因此该问题满足动态规划的最优子结构性质;同时状态dp[i][j]只依赖上方、左侧已经计算完成的状态,满足无后效性。

1.2 填表法设计
1.表格维度:二维表dp[N+1][N+1]下标从 1 开始,规避下标 0 的边界判断麻烦。
2.填表范围:i属于[1,N],j属于[1,N],覆盖整个 N 行 N 列网格。
3.填表顺序:
第一步:初始化起点 dp[1][1]
第二步:依次填充第一行(从左往右)、第一列(从上往下)两条边界
第三步:行优先遍历剩余区域,从上到下、每行内部从左向右填充 i>=2,j>=2 的单元格
4.原问题最优值:表格元素dp[N][N],即右下角终点位置的值。

1.3 复杂度分析
1.时间复杂度:O(N^2)
总共有 N^2 个状态,每个状态仅执行一次取最小值和加法运算,单次操作是常数 O(1),总的时间开销和网格规模平方成正比。
2.空间复杂度:O(N^2)
代码中开辟 price、dp 两个二维变长数组,存储空间大小为 O(N^2)。

二、对动态规划算法的理解和体会
本章动态规划是求解最优问题的核心算法思想,和分治法、贪心算法既有联系,又存在明显区别。通过本单元一系列例题,包括矩阵连乘、最长公共子序列、01 背包以及本次最低通行费网格路径问题,我逐步建立起动态规划完整的解题思维框架。

动态规划的核心是自底向上求解重叠子问题。它适用问题必须满足二个关键要素:最优子结构、重叠子问题。
1.最优子结构:一个问题的最优解包含其子问题的最优解,这是动态规划可以递推的基础。它会记录所有子问题的最优结果,在多个子方案里择优,适用范围广。
2.重叠子问题:在递归分解问题时,很多子问题会被反复调用。分治法适合子问题互不重叠的场景,一旦子问题大量重复,分治递归就会产生巨额冗余计算。动态规划通过填表、存储子问题答案,每个子问题只计算一次,避免重复求解,大幅降低时间开销。

本单元的动态规划分为两种实现思路:自顶向下的备忘录法、自底向上的填表法。备忘录法更贴近递归思路,只计算需要用到的子问题;填表法按照预先设计好的顺序逐个填充 DP 表,也是本次作业使用的方式,逻辑清晰、运行稳定,也是算法题目中最主流的写法。不管哪种写法,解题的固定流程都是统一的:定义状态→推导状态转移方程→确定边界初始条件→规划计算顺序→取出最终最优解。其中状态定义是最难、最核心的一步,状态定义的好坏直接决定方程能不能写出来、程序能不能实现。

不同题型的 DP 模型也给我留下很深的印象:矩阵连乘是区间 DP,处理一段区间内的最优划分;LCS 是二维序列 DP,处理两个序列的匹配;01 背包是资源选择类 DP;而最低通行费属于网格路径 DP。虽然场景各不相同,但底层思想完全一致。同时我也意识到,很多题目会藏有约束条件,像本题的时间限制,直接限定了移动方向,简化状态转移。
对比本单元学过的其他算法:分治适合拆分独立子问题,而动态规划是处理多阶段决策最优问题的强大工具。

posted on 2026-11-03 23:09  芋泥奶酪包  阅读(4)  评论(0)    收藏  举报