递归和动态规划——矩阵的最小路径和

本文介绍了如何使用动态规划解决从矩阵左上角到右下角的最小路径问题。通过分析第一行和第一列的特殊情况,以及一般位置的递推公式,展示了动态规划的思路。同时提到了一种压缩空间的方法,通过滚动更新数组来节省存储空间。
摘要由CSDN通过智能技术生成

《程序员代码面试指南》
动态规划问题
左上角到右下角,只能向下一步或者向右一步。
矩阵m的大小M*N,dp[i][j]表示从左上角到(i,j)的最小路径。dp[M][N]是答案。
第一行比较特殊,(0,0)到(0,j)只能向右,所以路径和是叠加。
第一列同理,(0,0)到(i,0)只能向下,路径和也是叠加。
此外的位置,dp[i][j] = min(dp[i-1][j],dp[i][j-1])+m[i][j]

//借鉴了牛客上的一些答案和书上答案
#include <vector>
#include <iostream>
using namespace std;
int minPathSum(vector<vector<int>> m){
        int row =m.size();
        int col = m[0].size();
        vector<vector<int>> dp(row,vector<int>(col,0));
        dp[0][0] = m[0][0];
        for (int i = 1; i< row; i++){
            dp[i][0]=dp[i-1][0]+m[i][0];
        }
        for (int j = 1; j< col; j++){
            dp[0][j]=dp[0][j-1]+m[0][j];
        }
        for (int i = 1; i < row; i++)
        {
            for (int j = 1; j< col; j++){
                dp[i][j] = min(dp[i-1][j],dp[i][j-1])+m[i][j];
            }
        }
        return dp[row-1][col-1];
}
int read() {
    int ans = 0, flag = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') {
            ch = getchar();
            flag = -1;
            break;
        }
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        ans = (ans << 3) + (ans << 1) + ch - '0';
        ch = getchar();
    }
    return ans * flag;
}

int main() {
    int N, M;
    N = read();
    M = read();
    vector<vector<int>> a(N,vector<int>(M,0));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            a[i][j] = read();
        }
    }
    cout<<minPathSum(a);
    return 0;
}

另外看到一个这么写的,感觉这样读取输入很方便(太久没写c++了,多积累点是一点T T)

	vector<vector<int> >a;
    int n,m;
    while(cin>>n>>m)
    {
        for(int i=0;i<n;i++)
        {
            vector<int>temp;
            for(int j=0;j<m;j++)
            {
                int tmp;
                cin>>tmp;
                temp.push_back(tmp);
            }
            a.push_back(temp);
        }
        cout<<minPathSum(a)<<endl;
    }

压缩空间的方法:

int minPathSum(vector<vector<int>> m){
        int row =m.size();
        int col = m[0].size();
        //vector<vector<int>> dp(row,vector<int>(col,0));
        int more = max(row,col);
        int less = min(row,col);
        bool rowmore= more==row;
        int dp[less];
        dp[0] = m[0][0];
        for(int i=1;i<less;i++){
            dp[i] = dp[i-1]+(rowmore?m[0][i]:m[i][0]);
        }
        for (int i = 1;i < more; i++)
        {    dp[0] = dp[0]+(rowmore?m[i][0]:m[0][i]);
            for (int j = 1; j< less; j++){
                dp[j] = min(dp[j-1],dp[j])+(rowmore?m[i][j]:m[j][i]);
            }
        }
        return dp[less-1];
}

如果行数多,先将数组初始化dp[less],dp[j]为(0,0)到(0,j)的最小路径和。
看(1,0),dp[0] = dp[0]+m[1][0].
(1,1),dp[1]=min(dp[0]+dp[1])+m[1][1]

不断滚动更新数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值