矩阵的最小路径和

博客围绕矩阵最小路径和问题展开。给定矩阵M,从左上角到右下角,每次只能右或下走,求最小路径和。题解使用动态规划,先给出常规解法,空间复杂度为O(MN),后介绍将其降为O(min(M,N))的方法,根据行列大小分情况处理。

题目描述

给定一个矩阵M,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。(难度:简单,降低空间复杂度)

题解

dp[i][j]表示到达该位置的最小路径和。

  • 当i=0,j>0时dp[i][j]=dp[i][j-1]+m[i][j]
  • 当j=0,i大于0时dp[i][j]=dp[i-1][j]+m[i][j]
  • 当i>0,j>0时dp[i][j]=min(dp[i-1][j],dp[i][j-1])+m[i][j]
  • 右下角的值即为最终的结果
  • 此时空间复杂度为O(MN),可以降为O(min(M,N))

假设矩阵M由m行,n列构成,如果m≥n,那么生成一个长度为n的数组arr,

  • 初始数组中存储第一行的路径和,
  • 当遍历第二行元素时,arr[0]=arr[0]+M[1][0],arr[1]=min(arr[0],arr[1])+M[1][1],
  • 依次重复此操作,因为下一行的值仅仅依赖于上一行和前一列,与其他位置无关。
  • 如果m小于n,那么初始就存储第一列的路径和,依次向右计算。
public int matrixPath(int[][]ma) {
		if(ma==null||ma.length==0||ma[0].length==0)
			return 0;
		int small=Math.min(ma.length,ma[0].length);
		int big=Math.max(ma.length,ma[0].length);
		int[] midSum=new int[small];
		midSum[0]=ma[0][0];
		boolean row=big==ma.length;//行大于列
		for(int i=1;i<small;i++) {
			midSum[i]=midSum[i-1]+(row?ma[0][i]:ma[i][0]);
		}
		for(int i=1;i<big;i++) {
			midSum[0]=midSum[0]+(row?ma[i][0]:ma[0][i]);
			for(int j=1;j<small;j++) {
				midSum[j]=Math.min(midSum[j-1], midSum[j])+
						(row?ma[i][j]:ma[j][i]);
			}
		}
		return midSum[small-1];
	}
在XDOJ平台上解决矩阵最小路径的问题,通常是指在一个二维矩阵中从左上角到右下角找到一条路径,使得路径上所有元素的最小。该问题可以通过动态规划(Dynamic Programming)的方法高效解。 ### 问题描述 假设给定一个 $ n \times m $ 的矩阵,其中每个位置 $(i, j)$ 上的值表示通过该位置所需付出的代价。目标是从起点 $(0, 0)$ 移动到终点 $(n-1, m-1)$,每次只能向右或向下移动一步,要找出所有可能路径中总代价最小的一条路径。 ### 动态规划解决方案 使用动态规划的思想来解决此问题。定义一个新的二维数组 `dp`,其中 `dp[i][j]` 表示从起点到达位置 $(i, j)$ 的最小路径。状态转移方程如下: - **初始条件**: - `dp[0][0] = matrix[0][0]`:起点的最小路径就是其自身的值。 - **状态转移方程**: - 如果是第一(即 $ i=0 $ 且 $ j>0 $),则只能从左边转移过来: ```cpp dp[i][j] = dp[i][j-1] + matrix[i][j]; ``` - 如果是第一(即 $ j=0 $ 且 $ i>0 $),则只能从上方转移过来: ```cpp dp[i][j] = dp[i-1][j] + matrix[i][j]; ``` - 如果是中间位置(即 $ i>0 $ 且 $ j>0 $),则可以从上方或左边选择较小的那个转移过来: ```cpp dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + matrix[i][j]; ``` 最终的答案就是 `dp[n-1][m-1]`,即终点位置的最小路径。 ### 示例代码实现 以下是一个完整的 C++ 实现示例: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int minPathSum(vector<vector<int>>& matrix) { int n = matrix.size(); int m = matrix[0].size(); // 创建 dp 数组 vector<vector<int>> dp(n, vector<int>(m, 0)); // 初始化第一个元素 dp[0][0] = matrix[0][0]; // 填充第一 for (int j = 1; j < m; ++j) { dp[0][j] = dp[0][j - 1] + matrix[0][j]; } // 填充第一 for (int i = 1; i < n; ++i) { dp[i][0] = dp[i - 1][0] + matrix[i][0]; } // 填充剩余部分 for (int i = 1; i < n; ++i) { for (int j = 1; j < m; ++j) { dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + matrix[i][j]; } } return dp[n - 1][m - 1]; } int main() { int n, m; cin >> n >> m; vector<vector<int>> matrix(n, vector<int>(m)); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { cin >> matrix[i][j]; } } cout << "最小路径为: " << minPathSum(matrix) << endl; return 0; } ``` ### 空间优化方案 如果希望进一步优化空间复杂度,可以将 `dp` 数组与原始矩阵合并使用原地更新,或者仅使用一维数组进优化。例如,使用一维数组 `dp` 来存储当前最小路径,逐步更新每一的结果。 ### 时间与空间复杂度分析 - **时间复杂度**:$ O(n \times m) $,需要遍历整个矩阵一次。 - **空间复杂度**:如果不进优化,为 $ O(n \times m) $;若使用一维数组优化,则可降低至 $ O(m) $ 或 $ O(n) $。 ### 总结 通过动态规划方法,可以在多项式时间内高效矩阵中的最小路径问题。该方法不仅适用于标准的 $ n \times m $ 矩阵,还可以扩展到其他类似的路径规划问题,如最大路径、带障碍物的路径等场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值