算法第三章作业
- 实践报告:题目“7-4 最低通行费”分析
(1.1) 最优子结构与递归方程式
状态定义:设 dp[i][j] 表示从网格左上角起点出发,走到坐标 (i, j) 位置时所需要的最低通行费。
最优子结构性质:由于每次只能向右或向下移动,因此到达位置 (i, j) 的路径必然是从其正上方 (i-1, j) 或正左方 (i, j-1) 走过来的。这意味着到达 (i, j) 的最优解,必然是由到达其上方和左方的最优解推导而来,符合最优子结构性质。
递归方程式:
dp[i][j] = cost[i][j] + min(dp[i-1][j], dp[i][j-1])
(注:cost[i][j] 表示当前格子本身的通行费用)
边界条件:
- 起点:dp[0][0] = cost[0][0] (网格左上角)
- 第一行(只能一直从左边向右走):dp[0][j] = dp[0][j-1] + cost[0][j] (j > 0)
- 第一列(只能一直从上边向下走):dp[i][0] = dp[i-1][0] + cost[i][0] (i > 0)
(1.2) 填表法分析
- 表的维度:二维数组 dp。假设网格大小为 N 行 M 列,则表的维度为 N × M。
- 填表范围:行索引 i 从 0 到 N-1,列索引 j 从 0 到 M-1。
- 填表顺序:从上到下,从左到右(即按行优先遍历)。因为计算当前元素 dp[i][j] 时,必须确保其依赖的上方元素 dp[i-1][j] 和左侧元素 dp[i][j-1] 已经计算完毕。
- 原问题的最优值:二维表格右下角的元素,即 dp[N-1][M-1]。
(1.3) 算法的时间和空间复杂度分析
- 时间复杂度:O(N × M)。算法需要遍历整个网格,填充 N × M 大小的二维数组,每个状态转移(计算 dp[i][j])只需要 O(1) 的常数时间。
- 空间复杂度:基础实现为 O(N × M),用于存储所有的状态值。由于计算第 i 行只依赖于第 i 行(左侧)和第 i-1 行(上方)的状态,可以通过“滚动数组”将其空间复杂度优化至 O(M)。
- 你对动态规划算法的理解和体会
动态规划(Dynamic Programming, DP)是一种解决多阶段决策过程最优化问题的算法思想,它的本质是“以空间换时间”,通过记录历史状态来避免重复计算。
通过本章的学习和实践,我有以下几点深刻体会:
第一,状态定义是灵魂。动态规划的第一步也是最难的一步,就是如何将一个复杂问题抽象为数学上的“状态”,并用数组(一维或二维)来精确表示。只有状态定义清晰,后续的转移才能顺理成章。
第二,状态转移方程是核心。它体现了问题中子问题之间的递推关系。在推导方程时,要时刻回顾“最优子结构”,即当前阶段的最优解能否由之前阶段的最优解推导得出。
第三,边界条件决定了算法的基石。很多时候代码逻辑写对了,但如果边界(如第一行、第一列)没有正确初始化,就会导致后续的状态推导全部出错。
第四,动态规划极大地锻炼了逻辑思维与抽象能力。它要求我们从局部最优推导全局最优,这种自底向上的思考方式在解决实际问题(如路径规划、资源分配、背包问题等)时非常高效且优雅。
总而言之,动态规划虽然入门时容易陷入“找不出递推式”的困境,但一旦理清思路、建立好模型,就能以极高的效率解决极其复杂的问题。
浙公网安备 33010602011771号