给定一个m行n列的矩阵,矩阵每个元素是一个正整数,你现在在左上角(第一行第一列),你需要走到右下角(第m行,第n列),每次只能朝右或者下走到相邻的位置,不能走出矩阵。走过的数的总和作为你的得分,求最大的得分。


  初看此题,你的思路是什么?

 
(1) 贪心? 先走到大的数再说?看这个例子:
无论你以什么方式走到3,总和都是1 + 1 + 3 + 1 + 1 + 1 + 1 = 9
我们为了1个3,放弃了那么多个2, 不值啊。如果我们放弃3而走那些2, 得到的和是1 + 1 + 2 + 2 + 2 + 1 + 1 = 10
看来贪心是错的! 因为我们走到最大值时有很多值不能走到了,一个最大值会把我们带沟里去。
(2) 枚举?枚举是万能的嘛。

可以试试,有多少条可能的路径?

你需要往下走(m – 1)次,往右走(n – 1)次,才能走到右下角,一共走m + n – 2步!可行路径的总条数有C(m + n – 2, m - 1)。
每条路径长度是m + n – 1 ,所以总的时间复杂度是O(C(m + n – 2, m – 1) * (m + n – 1)), 试试看m = n = 100时,这个数有多大吧!
没办法了么?
 
 (19899)=22750883079422934966181954039568885395604168260154104734000
想想看,问题有什么性质?

我们只能往右边或者下边走,意味着“不走回头路”,就是说矩阵里面每个位置最多只会经过一次。其实很多地方是“没有机会”经过的。比如我现在在第x行第y列,不管之前走的路径是什么样子,则它左边和上边的位置都是不可能再走到的,对吗?也就是说,我先在在矩阵第x行第y列,并假设以它为原点把矩阵分成四个“象限”,只有第四象限的位置才有可能从这以后经过 (当然还包括横轴的正半轴)!
 
假设我们从起点走到终点的过程中经过第x行第y列某个位置,为了从起点到终点得到的和最大,那么从起点到第x行第 y列这个位置经过的数的和也一定要最大。这几乎是显然的,但是你要刨根问底的话,可能要问为什么会这样呢?
我们定义集合A是从起点到第x行第y列的全部路径集合,定义集合B是从第x行第y列到终点的全部路径集合。那么起点到终点的路径实际上是子路径a∈A和子路径b∈B的连接(注意删掉第x行第y列这个点,否则走了两次了,呵呵)。

即所有经过第x行第y列的路径都可以划分到A和B这两个集合里,而且任何a∈A和子路径b∈B都可以拼接出一条经过第x行第y列的路径。
那么我要选择一条经过x,y的能得到最大值的路径,显然要选择A集合里路径和最大的a,(其实还要选B集合里和路径和最大的b)。
说了这么多,其实就是想明确一个事:从起点到终点的最优路径上经过了(m + n – 1)个点,则这条路径上对应起点到这(m + n – 1)个点的子路径也都从起点到该位置的所有路径中和最大的路径。
那么假设我们定义f(int x,int y)表示从起点到第x行第y列的最优路径上的数之和,并假设这个矩阵事个二维数组A[][] (下标从1开始)

我们考虑一下,我们如何才能到(x,y)?前一步要么到(x – 1, y), 要么到(x, y – 1),因为有且只有这两个位置能到(x,y),那么怎样才能得到f(x,y)?按我们前面说的,如果从起点达到(x,y)的最优路径要经过(x – 1,y)或者(x,y – 1)则,从起点到达(x – 1,y)或者(x,y – 1)的路径一定也必须是最优的。
那么按照我们对f的定义,我们有从起点达到x,y的最优路径有两种可能:
要么f(x – 1, y) + A[x][y]
要么f(x, y – 1) + A[x][y]
我们要取最优,那自然取较大的
因此有f(x, y) = max(f(x – 1, y) , f(x, y – 1) ) + A[x][y]
这样原来要枚举指数条路径,现在对于每个位置只有两种情况啦。
有了递推关系还不够,有初值才能求解。

那我们看一下 f(1,1),显然这是在起点,没的选f(1,1) = A[1][1]。
那么按照递推式 f(1,2) = max(f(0, y) , f(1,1)) + A[1][2], 但是我们对f(0, y)没有定义呀!考虑下实际意义,这表示要么我们从上面到达(1,2)要么从左面到达(1,2),可是上面没有位置过来啊,这种说明没的选。所以我们可以定义f(0, y) = -∞, 同理我们也可以定义f(x, 0)  = -∞。

那么总结一下我们的递推式

分析一下这个算法的时间复杂度? 显然是O(m * n),空间复杂度也一样,因为我们打出了一张(m + 1) * (n + 1)的表格——因此空间也是O(m * n)的。

再走一步?

我们找到了最大的和,如何得到和最大的路径呢? 还是从递推式入手,我们发现如果f(x,y) = f(x – 1,y) + A[x][y] 则它是从上面过来的,所以前一个位置是(x – 1, y)
否则 f(x, y) = f(x, y – 1) + A[x][y]则它是从左面过来的,所以前一个位置是(x, y- 1)。
这看起来最优路径被唯一确定了? 不是的,事实上当f(x – 1,y) = f(x, y – 1)时,前一个位置在上面或者左面都可以——所以路径还是很多很多的!

通过这个例子,你是不是对动态规划有了更深刻的理解呢?

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,a[][],dp[][];
int main()
{
cin>>n;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
cin>>a[i][j];
dp[i][j]=-;
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
dp[i][j]=max(dp[i][j-],dp[i-][j])+a[i][j];
cout<<dp[n][n];
}

如果对你有所帮助,别忘了加好评哦;么么哒!!下次见!88

- > 动规讲解基础讲解四——矩阵取数的更多相关文章

  1. 51Nod 1083 矩阵取数问题(矩阵取数dp,基础题)

    1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下 ...

  2. 1084 矩阵取数问题 V2

    1084 矩阵取数问题 V2 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下 ...

  3. NOIP2007 矩阵取数游戏

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

  4. NOIP2007矩阵取数[DP|高精度]

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

  5. TYVJ 矩阵取数 Label:高精度+dp

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

  6. 【NOIP2007】矩阵取数

    因为傻逼写错高精度搞了一下午浪费好多时间,好想哭qaq 原题: 帅帅经常更同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij据为非负整数.游戏规则如下: 1. 每次取数时须从每 ...

  7. 51nod1084 矩阵取数问题 V2

    O(n4)->O(n3)妈呀为什么跑这么慢woc #include<cstdio> #include<cstring> #include<cctype> #i ...

  8. 1166 矩阵取数游戏[区间dp+高精度]

    1166 矩阵取数游戏 2007年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description [ ...

  9. 矩阵取数游戏 NOIP 2007

    2016-05-31 17:26:45 题目链接: NOIP 2007 矩阵取数游戏(Codevs) 题目大意: 给定一个矩阵,每次在每一行的行首或者行尾取一个数乘上2^次数,求取完最多获得的分数 解 ...

随机推荐

  1. 实现grep命令

    #include <stdio.h> #include <string.h> #include <stdlib.h> // grep命令:grep match_pa ...

  2. 二分搜索 HDOJ 2289 Cup

    题目传送门 /* 二分搜索:枚举高度,计算体积与给出的比较. */ #include <cstdio> #include <algorithm> #include <cs ...

  3. 全面学习ORACLE Scheduler特性(1)创建jobs

    所谓出于job而胜于job,说的就是Oracle 10g后的新特性Scheduler啦.在10g环境中,ORACLE建议使用Scheduler替换普通的job,来管理任务的执行.其实,将Schedul ...

  4. SpringBoot 2.x (1):手动创建项目与自动创建项目

    SpringBoot 2.x基于Spring Framework 5.x 环境需求如下: JDK1.8或以上 Maven3.2或以上 这里我使用的是Eclipse,IDEA这个工具很强大,但不习惯它 ...

  5. JavaScript开发心得--如何传递某行数据给下一页

    1, 应用场景 在某个html页面显示一批数据,如20个用户的名称.年龄等,每行都要一个编辑按钮,点击编辑后,将此行数据带入某个专门的编辑页进行显示,修改后保存. 问题是 点击编辑按钮后,如何得知要编 ...

  6. PHP开发心得一

    1,php获得服务器时间 $time= date('Y-m-d H:i'); echo $time; 一般写法如上,但发现打印出来的时间小时数总数不对,和机器的时间差几个小时.查资料发现,要设定时区. ...

  7. [iOS]查看苹果支持的所有字库

    有时候,在开发的时候,想换个字体更加优雅的显示.但是不知道苹果本身到底支持了那些字体,怎么办? 没关系,打开这个网址:http://iosfonts.com/ 所见即所得,非常方便,而且还表明了从那个 ...

  8. Java基础(二)--this关键字及初始化

    构造器: 构造器的名称必须和类名完全相同,所以一般方法的"首字母小写"命名规则并不适合构造器 默认构造器: 也叫无参构造器,作用就是创建一个默认对象,如果你不是手写出来,编译器默认 ...

  9. java虚拟(一)--java内存区域和常量池概念

    一.java运行时数据区 也可以称为java内存区域,和java内存模型不是一回事,不要弄混,这里基于jdk1.8之前 1.1.方法区 线程共享,类装载过程中产生的java.lang.Class对象保 ...

  10. 【转载】jQuery.extend 函数详解

    转载自:http://www.cnblogs.com/RascallySnake/archive/2010/05/07/1729563.html jQuery.extend 函数详解 JQuery的e ...