数字三角形问题 (动态规划初步)
2016-03-30 21:17
197 查看
问题描述:
有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外每个数的左下方和右下方各有一个数。
从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来。如何走才能使得这个和尽量大?
如下图:
1
3 2
4 10 1
4 3 2 20
思考:把当前的位置(i,j)看成一个状态,然后定义状态(i,j)的指示函数d(i,j)为从格子(i,j)出发时能得到的最大和(包括格子(i,j)本身的值)。在这个状态定义下,原问题的解释d(1,1)。
状态状态转移:从格子(i,j)出发有两种决策。如果往左走,则走到(i+1,j)后需要求”从(i+1,j)出发后能得到的最大和”这一问题,即d(i+1,j)。类似的,往右走之后需要求解d(i+1,j+1)。
所以状态转移方程就是d(i,j)=max{d(i+1,j),d(i+1,j+1)}+a(i,j);
方法一:递推计算 (时间复杂度为O(n^2))
因为i是枚举的,因此在计算 d[i][j] 前,它所需要的d[i+1][j]和d[i+1][j+1]一定已经计算出来了
方法二:记忆化搜索(时间复杂度O(n^2) 首先memset(d,-1,sizeof(d)) 将d全部初始化为-1
题目中各个数都是非负的,这样只需要把d初始化为-1,即可通过判断是否d[i][j]>=0得知它是否已经被计算过。
有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外每个数的左下方和右下方各有一个数。
从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来。如何走才能使得这个和尽量大?
如下图:
1
3 2
4 10 1
4 3 2 20
思考:把当前的位置(i,j)看成一个状态,然后定义状态(i,j)的指示函数d(i,j)为从格子(i,j)出发时能得到的最大和(包括格子(i,j)本身的值)。在这个状态定义下,原问题的解释d(1,1)。
状态状态转移:从格子(i,j)出发有两种决策。如果往左走,则走到(i+1,j)后需要求”从(i+1,j)出发后能得到的最大和”这一问题,即d(i+1,j)。类似的,往右走之后需要求解d(i+1,j+1)。
所以状态转移方程就是d(i,j)=max{d(i+1,j),d(i+1,j+1)}+a(i,j);
方法一:递推计算 (时间复杂度为O(n^2))
int i,j; for(i=1; i<=n; ++i) //下标从1开始 d [i]=a [i]; for(i=n-1; i>=1; --i){ for(j=1; j<=i; ++j) d[i][j]=a[i][j]+max(d[i+1][j],d[i+1][j+1]); }
因为i是枚举的,因此在计算 d[i][j] 前,它所需要的d[i+1][j]和d[i+1][j+1]一定已经计算出来了
方法二:记忆化搜索(时间复杂度O(n^2) 首先memset(d,-1,sizeof(d)) 将d全部初始化为-1
int solve(int i, int j){ if(d[i][j]>0) return d[i][j]; return d[i][j] = a[i][j] + ( i==n ? 0 : max(solve(i+1, j), solve(i+1, j+1) ) ); }
题目中各个数都是非负的,这样只需要把d初始化为-1,即可通过判断是否d[i][j]>=0得知它是否已经被计算过。
相关文章推荐
- linux中使用svn客户端【新浪云搬运】
- 百度2016校园招聘编程题解析
- 关于大型网站技术演进的思考(五)--存储的瓶颈(5)
- Android内存泄漏的各种原因详解
- 百万条数据快速查询优化技巧
- HDU 5249 离线树状数组求第k大+离散化
- 【目录】JVM目录
- 存储过程的优点和缺点
- 笔记 - Java 反射
- MyEclipse安装插件代码生成器
- ARMv8架构下程序运行时栈帧布局
- 关于大型网站技术演进的思考(六)--存储的瓶颈(6)
- <string.h>
- 完成命令解析程序
- Java语言类库中几个常用的包
- .gitignore无效,不能过滤某些文件
- Java数据结构——用双端链表实现队列
- Android UI杂谈---layout_weight
- Spring 框架的 UI(IOC) 功能
- python类中的__call__、__init__、__getattr__、__setattr__、__setattr__详解