矩阵从左上角向右下角走,每次只能向右或者向下移动,求经过最小的路径

本文介绍了一种使用动态规划寻找矩阵中从起点到终点的最小路径的方法,并通过一个示例程序详细展示了如何实现这一算法。从初始化边界条件开始,逐步递推至目标位置,最后逆向追踪得到具体的路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先通过动态规划求出最小路径的值,然后根据dp二维数组倒推所走路径。参考找出最大公共子序列解法。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int minsum(vector<vector<int>>a, vector<int>&reg){
    vector<vector<int>>dp(a.size(), vector<int>(a[0].size(), a[0][0]));
    
    for (int i = 1; i < a.size(); i++){
        dp[i][0] = dp[i - 1][0]+a[i][0];
    }
    for (int j = 1; j < a[0].size(); j++){
        dp[0][j] = dp[0][j - 1] + a[0][j];
    }
    for (int i = 1; i < a.size(); i++){
        for (int j = 1; j < a[0].size(); j++){
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
        }
    }
    /*for (int i = 0; i < dp.size(); i++){
        for (int j = 0; j < dp[0].size(); j++){
            cout << dp[i][j] << " ";
        }
        cout << endl;
    }*/
    
    int i = dp.size() - 1;
    int j = dp[0].size() - 1;
    while (i >= 0 && j >= 0){
        reg.push_back(a[i][j]);
        if (i > 0 && j > 0){
            if (dp[i][j - 1] > dp[i - 1][j]){
                i--;
            }
            else{
                j--;
            }
            continue;
        }
        else if (i == 0){
            j--;
        }
        else{
            i--;
        }
    }
    return dp[a.size()-1][a[0].size()-1];
}

int main(){
    vector<vector<int>>a = { { 1, 3, 1 }, { 1, 5, 1 }, { 4, 2, 1 } };
    vector<int>reg;
    int res = minsum(a,reg);
reverse(reg.begin(), reg.end());
for (int i = 0; i < reg.size(); i++){ cout << reg[i] << endl; } system("pause"); return 0; }

 

转载于:https://www.cnblogs.com/inception6-lxc/p/9316782.html

<think>首先,用户的问题是关于在二维网格中找到从左上角到右下角最小路径每次只能向右向下移动。这是一个经典的动态规划问题。 我需要参考用户提供的引用内容。引用[1]描述了问题,引用[2]、[3]、[4]、[5]提供了动态规划的解决方案。这些引用包括JavaC++的代码实现,以及一些解释。 关键点: - 网格大小是m行n列。 - 每个单元格包含非负整数。 - 只能向右向下移动。 - 目标是找到从(0,0)到(m-1,n-1)的路径,其路径最小。 动态规划思路: 1. 创建一个dp数组,大小网格相同,dp[i][j]表示从(0,0)到(i,j)的最小路径。 2. 初始化: - dp[0][0] = grid[0][0],因为起点就是它本身。 - 对于第一行(i=0),只能向右,所以dp[0][j] = dp[0][j-1] + grid[0][j]。 - 对于第一列(j=0),只能向下,所以dp[i][0] = dp[i-1][0] + grid[i][0]。 3. 对于其他单元格(i>0且j>0),dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j],因为可以从上方或左方移动过来。 4. 最终结果在dp[m-1][n-1]。 引用[4]提到空间复杂度可以优化到O(n),通过只存储一行或一列的值。 我的回答需要: - 使用中文。 - 结构清晰,逐步解释。 - 包含LaTeX公式:行内用$...$,独立公式用$$...$$。 - 在回答末尾生成相关问题。 - 自然地添加引用标识。 回答结构: 1. **问题描述**:简要重述问题。 2. **动态规划思路**:解释算法步骤。 3. **状态转移方程**:用LaTeX写公式。 4. **代码实现**:提供Python代码,因为用户示例中有Python代码。 5. **复杂度分析**:时间空间复杂度。 6. **空间优化**:简要提到优化方法。 7. **生成相关问题**:在最后添加相关问题。 生成相关问题: 基于用户的问题,相关问题可以是: 1. 如何优化空间复杂度? 2. 如果网格中有负数怎么办? 3. 如何扩展到允许对角线移动? 4. 实际应用场景是什么? 引用标识:在相关地方添加,如[^1]、[^2]等。 现在,构建回答: - 问题描述:用户已给出,我简要重述。 - 动态规划思路:逐步解释。 - 状态转移方程: - 初始:$dp[0][0] = grid[0][0]$ - 第一行:$dp[0][j] = dp[0][j-1] + grid[0][j]$ - 第一列:$dp[i][0] = dp[i-1][0] + grid[i][0]$ - 其他:$dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j]$ - 代码:用Python实现,因为用户示例是Python。 - 复杂度:时间O(mn),空间O(mn)(可优化到O(n))。 - 优化:提到滚动数组优化。 - 相关问题:列出3-4个。 确保LaTeX正确: - 行内:$dp[i][j]$ - 独立:$$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 引用: - 引用[1]描述问题,[^1] - 引用[2]、[3]、[5]有代码解释,[^2]、[^3]、[^5] - 引用[4]有空间优化,[^4] 在回答中自然地添加引用,如“根据动态规划方法[^2],我们可以...”</think>### 最小路径问题 您的问题是在一个 $m \times n$ 的二维网格中,从左上角 $(0,0)$ 出发,每次只能向右向下移动,最终到达右下角 $(m-1,n-1)$,目标是找到所有可能路径路径最小的值。路径定义为路径上所有网格数字的总。这是一个经典的动态规划问题,下面我将逐步解释解决方案。 #### 1. **动态规划思路** 动态规划的核心是构建一个状态数组 $dp$,其中 $dp[i][j]$ 表示从起点 $(0,0)$ 到达网格位置 $(i,j)$ 的最小路径。状态转移基于移动限制(只能向右向下): - **起点**:$dp[0][0]$ 就是网格起点值。 - **边界处理**: - **第一行($i=0$)**:只能向右移动,因此 $dp[0][j] = dp[0][j-1] + grid[0][j]$。 - **第一列($j=0$)**:只能向下移动,因此 $dp[i][0] = dp[i-1][0] + grid[i][0]$。 - **一般位置($i>0$ 且 $j>0$)**:可以从上方 $(i-1,j)$ 或左方 $(i,j-1)$ 移动过来,选择路径更小的方向: $$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 最终,$dp[m-1][n-1]$ 即为所最小路径[^2][^3][^5]。 #### 2. **算法步骤** 1. **初始化**: - 若网格为空,返回 0。 - 创建 $dp$ 数组,大小网格相同。 - $dp[0][0] = grid[0][0]$。 2. **填充边界**: - 遍历第一行:$dp[0][j] = dp[0][j-1] + grid[0][j]$($j$ 从 1 到 $n-1$)。 - 遍历第一列:$dp[i][0] = dp[i-1][0] + grid[i][0]$($i$ 从 1 到 $m-1$)。 3. **填充内部**: - 双重循环遍历 $i$ 从 1 到 $m-1$,$j$ 从 1 到 $n-1$: $$ dp[i][j] = \min(dp[i-1][j], dp[i][j-1]) + grid[i][j] $$ 4. **返回结果**:$dp[m-1][n-1]$。 #### 3. **代码实现(Python)** 以下是完整的 Python 实现,代码注释详细解释了每一步: ```python def minPathSum(grid): if not grid or not grid[0]: return 0 m, n = len(grid), len(grid[0]) # 初始化 dp 数组 dp = [[0] * n for _ in range(m)] dp[0][0] = grid[0][0] # 起点 # 填充第一行 for j in range(1, n): dp[0][j] = dp[0][j-1] + grid[0][j] # 填充第一列 for i in range(1, m): dp[i][0] = dp[i-1][0] + grid[i][0] # 填充其他位置 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 (路径 1→1→4→2→1 或 1→1→2→1→1) ``` #### 4. **复杂度分析** - **时间复杂度**:$O(m \times n)$,因为需要遍历整个网格一次。 - **空间复杂度**:$O(m \times n)$,用于存储 $dp$ 数组。但可以优化到 $O(n)$(或 $O(m)$),通过只存储一行或一列的值(滚动数组优化)[^4]。 #### 5. **空间优化方法** 通过滚动数组优化空间: - 使用一维数组 $dp$ 代替二维数组。 - 更新规则: - 初始化 $dp[0] = grid[0][0]$。 - 第一行:$dp[j] = dp[j-1] + grid[0][j]$。 - 后续行:$dp[0]$ 更新为 $dp[0] + grid[i][0]$(第一列),然后 $dp[j] = \min(dp[j], dp[j-1]) + grid[i][j]$(其他列)。 - 优化后空间复杂度为 $O(n)$[^4]。 ### 相关问题 基于最小路径问题,以下是几个延伸问题: 1. **如何优化最小路径算法的空间复杂度?**(例如,使用滚动数组将空间复杂度从 $O(mn)$ 降到 $O(n)$) 2. **如果网格中存在负数,动态规划方法是否仍然有效?需要如何调整?** 3. **最小路径问题在实际应用中有哪些场景?**(例如,机器人导航、资源优化等) 4. **如何扩展问题以允许对角线移动?动态规划状态转移方程会如何变化?** [^1]: [分支限界]给定一个矩阵m*n,从左上角开始每次只能向右或者向下,最后到右下角的位置共有多少种路径给定一个m行n列的矩阵,从左上角开始每次只能向右向下移动,最后到达右下角的位置,路径上的所有数字累加起来作为这条路径路径。编写程序所有路径中的最小路径。 [^2]: 64. 最小路径给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角路径,使得路径...。使用动态规划的方法解决。 [^3]: 64. 最小路径 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角路径,使得路径上...。说明:每次只能向下或者向右移动一步。 [^4]: 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角路径,使得路径上的数字总最小...。空间复杂度可以优化,例如每次只存储上一行的 dp 值,则可以将空间复杂度优化到 O(n)。 [^5]: m x n 网格,请找出一条从左上角到右下角路径,使得路径上的数字总最小。说明:每次只能向下或者向右移动一步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值