动态规划求最小路径和

70 阅读2分钟

动态规划求最小路径和

动态规划是一种常用的算法策略,适用于具有重叠子问题结构的问题。本文将探讨如何利用动态规划来解决一个经典的路径选择问题——寻找从矩阵左上角到右下角的最小路径和。

问题描述

给定一个 mtimesnm \\times n 的网格(矩阵),其中每个单元格包含非负整数,你需要找到一条从左上角 (0,0)(0,0) 到右下角 (m1,n1)(m-1,n-1) 的路径。每次只能向右或向下移动一步,并且需要使路径上的数字之和最小。

动态规划思想

动态规划的核心在于将大问题分解为小问题并利用这些小问题的结果来解决原问题。对于本题,我们可以定义一个二维数组 dpdp,其中 dp\[i\]\[j\] 表示从起点 (0,0)(0,0) 到达位置 (i,j)(i,j) 的最小路径和。

  1. 状态转移方程:在到达某个位置时,只能是从上方或左方移动过来。因此,我们有: [ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] ]

  2. 边界条件:起点 (0,0)(0, 0) 的值即为 grid\[0\]\[0\]

  3. 最终结果:目标是最小路径和,即 dp\[m-1\]\[n-1\]

具体步骤

第一步:初始化

  • 初始化一个大小与给定矩阵相同的二维数组 dpdp
  • 将起点位置 (0,0)(0, 0) 的值设为 grid\[0\]\[0\],表示从这里出发的最小路径和即为该元素本身的值。

第二步:状态转移

  • 依次计算每个单元格的位置 (i,j)(i,j)dp\[i\]\[j\] 值。对于除起点外的所有位置: [ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] ]

第三步:结果

  • 最终,dp\[m-1\]\[n-1\] 即为从左上角到右下角的最小路径和。

示例代码

def minPathSum(grid):
    if not grid or not grid[0]:
        return 0

    m, n = len(grid), len(grid[0])
    dp = [[0] * n for _ in range(m)]

    # 初始化起点位置
    dp[0][0] = grid[0][0]

    # 填充第一列的dp值
    for i in range(1, m):
        dp[i][0] = dp[i-1][0] + grid[i][0]

    # 填充第一行的dp值
    for j in range(1, n):
        dp[0][j] = dp[0][j-1] + grid[0][j]

    # 动态规划计算其他位置
    for i in range(1, m):
        for j in range(1, n):
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

    return dp[m-1][n-1]

# 示例
grid = [
    [1, 3, 1],
    [1, 5, 1],
    [4, 2, 1]
]
print(minPathSum(grid))  # 输出:7

通过动态规划,我们可以有效地解决最小路径和问题。这种方法不仅适用于矩阵,也可以推广到更复杂的问题结构中去。