第三章作业
实践报告:动态规划求解最低通行费
1.动态规划法的求解步骤分析作业
1.1 根据最优子结构性质,列出递归方程式,说明方程式的定义、边界条件
题意分析
题目要求商人从左上角走到右下角,必须在2N-1个单位时间到达。网格里一步走一格,总步数固定为2N-1,说明路径只能向右或者向下走,如果往上或者往左走,步数就会超标,无法按时到达终点。设网格费用数组为a[i][j],代表第i行第j列方格的通行费用。定义dp[i][j]:从左上角(1,1)走到((i,j)位置时的最小总通行费用。
递归方程
dp[i][j] = a[i][j] + min(dp[i-1][j],dp[i][j-1]))含义:走到(i,j)只能是从上方(i-1,j)向下走过来,或者从左边(i,j-1)向右走过来,取两条路径里费用更小的那一条,再加上当前格子本身的费用。
边界条件
- 起点dp[1][1] = a[1][1],起点位置的最小费用就是自己格子的费用;
- 第一行(i=1,j>1)第一行不能从上方来,只能一直向右走dp[1][j] = dp[1][j-1] + a[1][j]
- 第一列(j=1,i>1)第一列不能从左边来,只能一直向下走dp[i][1] = dp[i-1][1] + a[i][1]
最优子结构,走到(i,j)的最优路径,它前面走到(i-1,j)和(i,j-1)的那段路径也一定是最优的;如果前面有更便宜的走法,替换之后就能得到更优解,满足动态规划最优子结构。
1.2 填表法中表的维度、填表范围和填表顺序,以及原问题的最优值是哪个表格元素
1.表格维度,dp 是一个N*N的二维表格,和费用网格一样大小
2.填表范围,i 从 1 到 N,j 从 1 到 N
3.填表顺序,先填边界:第一行从左往右依次填,第一列从上往下依次填,再填内部单元格,按从上到下、逐行填写,每行内部从左往右的顺序。保证计算dp[i][j]的时候,它左边 dp[i][j-1]和上边dp[i-1][j]的值已经提前算好;
4.原问题最优值,dp[N][N],也就是表格右下角元素,代表走到右下角终点的最小总费用。
1.3 分析该算法的时间和空间复杂度
时间复杂度:O(N^2)一共NN个单元格,每个单元格只做一次min比较和加法运算,单次计算是常数时间。
空间复杂度:O(N^2)我们开了大小为NN的dp二维数组
2.对动态规划算法的理解和体会
作为大二学生,做完这道最低通行费的题目之后,我对动态规划有了更实在的理解。之前上课的时候总觉得动态规划很抽象,只记住了 “最优子结构” 和 “重叠子问题” 这两个名词,不太明白什么时候该用。这道题让我意识到,动态规划本质就是把一个大的最优问题拆成一个个小一点的子问题,把子问题的答案存起来反复用,避免暴力搜索里大量重复计算。
这道题有个很巧妙的限制:必须在2N-1时间到达终点,直接帮我们筛掉了回头路,路径只剩下向右、向下两种选择,一下子就简化了状态转移。我也意识到,拿到动态规划题目,第一步不是急着写代码,而是先想清楚状态怎么定义,再去推导转移方程。状态定义好不好,直接决定题目能不能顺利做出来。
对比暴力枚举所有路径,动态规划不用一条条路径全部遍历,而是用一张 dp 表记录每一个位置的最优结果,后面的结果直接查表,效率高很多。当然它也有局限,需要问题满足最优子结构和无后效性,后面的选择不会影响前面已经算好的子问题结果。
总的来说,动态规划是一种 “以空间换时间” 的思想。填表的过程就像是一步步累积最优解,从小规模推到大规模。以后遇到最短路径、最值类的问题,我会先想一想能不能拆分成子问题、能不能记录中间状态,尝试用动态规划的思路去解决。
浙公网安备 33010602011771号