LeetCode:Minimum Path Sum(网格最大路径和)

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.


典型的动态规划问题。

设dp[i][j]表示从左上角到grid[i][j]的最小路径和。那么dp[i][j] = grid[i][j] + min( dp[i-1][j], dp[i][j-1] );

下面的代码中,为了处理计算第一行和第一列的边界条件,我们令dp[i][j]表示从左上角到grid[i-1][j-1]的最小路径和,最后dp[m][n]是我们所求的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        int row = grid.size(),col;
        if(row == 0)return 0;
        else col = grid[0].size();
        vector<vector<int> >dp(row+1, vector<int>(col+1, INT_MAX));
        dp[0][1] = 0;
        for(int i = 1; i <= row; i++)
            for(int j = 1; j <= col; j++)
                dp[i][j] = grid[i-1][j-1] + min(dp[i][j-1], dp[i-1][j]);
        return dp[row][col];
    }
};

 

注意到上面的代码中dp[i][j] 只和上一行的dp[i-1][j]和上一列的dp[i][j-1]有关,因此可以优化空间为O(n)(准确来讲空间复杂度可以是O(min(row,col

)))                          本文地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public:
    int minPathSum(vector<vector<int> > &grid) {
        int row = grid.size(),col;
        if(row == 0)return 0;
        else col = grid[0].size();
        vector<int >dp(col+1, INT_MAX);
        dp[1] = 0;
        for(int i = 1; i <= row; i++)
            for(int j = 1; j <= col; j++)
                dp[j] = grid[i-1][j-1] + min(dp[j], dp[j-1]);
        return dp[col];
    }
};

问题扩展

最大路径和只需要把上面的递推公式中的min换成max。

现在有个问题,如果两个人同时从左上角出发,目的地是右下角,两个人的路线不能相交(即除了出发点和终点外,两个人不同通过同一个格子),使得两条路径的和最大。(这和一个人先从左上角到右下角,再回到左上角是相同的问题)。

这是双线程动态规划问题:假设网格为grid,dp[k][i][j]表示两个人都走了k步,第一个人向右走了i步,第二个人向右走了j步 时的最大路径和(只需要三个变量就可以定位出两个人的位置grid[k-i][i-1] 、 grid[k-j][j-1]),那么

dp[k][i][j] = max(dp[k-1][i-1][j-1], dp[k-1][i][j], dp[k-1][i-1][j], dp[k-1][i][j-1]) + grid[k-i][i-1] + grid[k-j][j-1]  (我们假设在起始位置时就已经走了一步)

 

这个方程的意思是从第k-1步到第k步,可以两个人都向右走、都向下走、第一个向下第二个向右、第一个向右第二个向下,这四种走法中选择上一步中路径和最大的。

 

由于要保证两条路线不能相交,即两个人走的过程中,有一个人向右走的步数永远大于另一个人向右走的步数,我们不妨设第二个人向右走的步数较大,即dp[k][i][j]中j > i才是有效的状态。走到终点的步数为:网格的行数+网格的列数-1

 

需要注意的是:当走了k步时,某个人向右走的步数必须 > k - 网格的行数,如果向右走的步数 <= k-行数,那么向下走的步数 = k-向右走的步数 >= 行数,此时超出了网格的范围。由于我们假设了 j > i,因此只要保证 i > k-网格行数即可。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int max2PathSum(vector<vector<int> > grid)
{
    int row = grid.size(), col = grid[0].size();
    vector<vector<vector<int> > > dp(row+col, vector<vector<int> >(col+1, vector<int>(col+1, 0)));
    for(int step = 2; step <= row+col-2; step++)
        for(int i = max(1, step-row+1); i <= step && i <= col; i++)
            for(int j = i+1; j <= step && j <= col; j++)
            {
                 
                dp[step][i][j] = max(max(dp[step-1][i][j], dp[step-1][i-1][j-1]), max(dp[step-1][i-1][j], dp[step-1][i][j-1]));
                dp[step][i][j] += (grid[step-i][i-1] + grid[step-j][j-1]);
            }
    return dp[row+col-2][col-1][col] + 2*grid[row-1][col-1] + 2*grid[0][0];
}

 

我们最终的目标是dp[row+col-1][col][col] = max{dp[row+col-2][col-1][col-1], dp[row+col-2][col][col], dp[row+col-2][col-1][col], dp[row+col-2][col][col-1]} + 2*grid[row-1][col-1]

由于dp[row+col-2][col-1][col-1], dp[row+col-2][col][col], dp[row+col-2][col][col-1]都是无效的状态(dp[k][i][j]中j > i才是有效的状态),

所以dp[row+col-1][col][col]  = dp[row+col-2][col-1][col] + 2*grid[row-1][col-1],代码中最后结果还加上了所在起点的的网格值。

由以上可知,循环中最多只需要求到了dp[row+col-2][][]。

 

nyoj中 传纸条(一)就是这个问题,可以在这一题中测试上述函数的正确性,测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        int row, col;
        scanf("%d%d", &row, &col);
        vector<vector<int> >grid(row, vector<int>(col));
        for(int a = 0; a < row; a++)
            for(int b = 0; b < col; b++)
                scanf("%d", &grid[a][b]);
        printf("%d\n", max2PathSum(grid));
    }
    return 0;
}

 

这个问题还可以使用最小费用流来解决,具体可以参考here

 






本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3774804.html,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

delete在js里为引用删除

delete 运算符从对象中删除一个属性&#xff0c;或从数组中删除一个元素。delete expressionexpression 参数是一个有效的 JScript 表达式&#xff0c;通常是一个属性名或数组元素。说明如果 expression 的结果是一个对象&#xff0c;且在 expression 中指定的属性存在&#xf…

C语言试题六十五之请编写函数实现猴子吃桃问题

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 猴子吃桃问…

百度:病种类贴吧全面停止商业合作

新浪科技讯 1月12日上午消息&#xff0c; 百度今日就热门疾病被出卖一事向新浪科技发布对外公告&#xff1a;病种类贴吧全面停止商业合作 只对权威公益组织开放。百度方面在公告中表示&#xff0c;为了规范具有明显商业属性贴吧的运营管理&#xff0c;并提升贴吧的内容质量和用…

【CSS动效实战(纯CSS与JS动效)】02 flex 布局实战(仿 JD 及 gitCode 布局)及 media 自适应初探

一、flex 仿 JD 布局 首先&#xff0c;我们在编辑器中&#xff0c;写上基础代码&#xff0c;当然要在 style 中加上一个 flex 类&#xff0c;用于 flex 布局的定义&#xff0c;这个是必然需要的&#xff0c;在此一定得加上。 <!DOCTYPE html> <html lang"en&qu…

C语言sin()函数绘制正弦曲线代码(0-2π)

本文实现y=sin(x)正弦曲线在0-2π范围内的曲线图形,如下图所示: 完整C语言代码: #include<stdio.h> #include<math.h> main() {double y; int x,m,i; printf

MAUI模板项目闪退问题

MAUI模板项目闪退问题在MAUI最初发布的时候就曾创建过几个模板项目进行体验过&#xff0c;没遇到什么坑。由于最近需要开发针对餐饮行业的收银机&#xff08;安卓系统&#xff09;开发一款应用&#xff0c;这种收银机一般配置不咋滴&#xff0c;系统版本和性能也肯定比不上我们…

真正CSDN博客文章一键转载插件(含源码)

插件地址&#xff1a;https://greasyfork.org/zh-CN/scripts/381053-csdn%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0%E8%BD%AC%E8%BD%BD%E6%8F%92%E4%BB%B6 插件安装使用说明请参阅&#xff1a;https://greasyfork.org/zh-CN 文章阅读界面 文章发布页面 源代码 // UserScript //…

Kotlin之集合排序(sortBy、sortByDescending)

1、Kotlin的集合排序 如果我们需要对一个集合里面的某个对象的一个字段进行排序,java的话需要实现一个比较器Comparator,Kotlin的针对集合里面的某个对象的一个字段进行排序非常简单,一行代码搞定。 2、sortBy方法、sortByDescending方法 1)、sortBy升序排列 2)、sortBy…

限制nginx仅能域名访问,不可用ip访问

在nginx.conf 文件里 初始时是&#xff1a; 12345server {listen 80 default_server; server_name www.lnmp.org; ... }修改成 12345server {listen 80; server_name yoursDomainName; #这里是你自己指定的域名 ... }再在上个server后继续添加一段&#xff1a; 12345server …

getElementByClassName()不兼容的解决办法

在获取元素时候采用getElementByClassName()方法是比较方便的&#xff0c;但是对于IE6不兼容&#xff0c;可以采用以下代码来自定义这个方法&#xff1a; window.οnlοadfunction(){ if(!document.getElementByClassName){ document.getElementByClassNamefunction(cls){ var …

学习C语言指针,这一篇案例教程就够够的了

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。 一个优秀的程序员最爱玩的就是指针! 通过本文10个案例的学习,你会对C语言指针的来龙去脉做一个全面的学习,直接用于实战开…

阻塞队列BlockingQueue用法

多线程环境中&#xff0c;通过队列可以很容易实现数据共享&#xff0c;比如经典的“生产者”和“消费者”模型中&#xff0c;通过队列可以很便利地实现两者之间的数据共享。 假设我们有若干生产者线程&#xff0c;另外又有若干个消费者线程。如果生产者线程需要把准备好的数据共…

C语言试题六十六之请编写函数实现三个数从小到大排序

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 对a、b、c…

微软欲闭源VS Code的C#扩展惹众怒

VS Code 是一个非常棒的代码编辑器&#xff0c;轻量&#xff0c;免费&#xff0c;跨平台。并且凭其丰富且强大的扩展功能受到众多开发者的青睐&#xff0c;你可以在上面愉快的进行各种语言的开发工作。就在前两天&#xff0c;微软的 .NET 和 Visual Studio 的项目经理 Tim Heue…

Python3.6学习笔记(三)

面向对象编程 面向对象编程 Object Oriented Programming 简称 OOP&#xff0c;是一种程序设计思想。OOP把对象作为程序的基本单元&#xff0c;一个对象包含了数据和操作数据的函数。 面向过程的程序设计把计算机程序视为一系列的命令集合&#xff0c;即一组函数的顺序执行。为…

EnumMap

什么是EnumMap Map接口的实现&#xff0c;其key-value映射中的key是Enum类型&#xff1b; 补充说明 其原理就是一个对象数组&#xff0c;数组的下标索引就是根据Map中的key直接获取&#xff0c;即枚举中的ordinal值&#xff1b; 效率比HashMap高&#xff0c;可以直接获取数组下…

【CSS动效实战(纯CSS与JS动效)】03 精美手风琴侧边栏完整示例教程 示例1

本节示例演示&#xff1a; 一、基本布局 一般来说&#xff0c;侧边栏的位置是在左侧&#xff0c;咱们为了更好的展现侧边栏的效果&#xff0c;并且在本节中不涉及过多的内容&#xff0c;我们只需要直接给一个 div 宽度为 15即可&#xff0c;接着再到这个 div 中编写对应的侧…

ArcGIS实验教程——实验三十二:ArcGIS水文分析(流向分析、计算水流长度、汇流分析、河网分析、流域分析)

ArcGIS实验视频教程合集:《ArcGIS实验教程从入门到精通》(附配套实验数据)》 文章目录 一、流向分析1. 水流方向计算方法2. 原始DEM流向分析3. 洼地判定4. 洼地填充5. 无洼地DEM流向分析二、计算水流长度三、汇流分析四、河网分析五、流域分析水文分析是数字地形分析的一个重…

C语言试题六十七之请编写函数实现水仙花数

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 输出所有“…

Yii框架操作方法

1.yii数据查询a.使用CDbCriteria数据查询$attributes array();$criteria new CDbCriteria;//$criteria->selectamount; $criteria->conditionuser_id:user_id;$criteria->paramsarray(:user_id>18889195);$DwCouponModel new Coupon();$cla***esult $DwCoupon…