数字三角形(数塔问题)


其实动态规划本身并不是一个特定的算法,是一种用途广泛的问题求解方法,一种思想,一种手段。

1.1问题描述与状态定义


有一个有非负整数组成的三角形,第一行一个数字,下面各行除了最后一行外,每行的每个数字下面左右各一个数字。
如图示:

从第一行数字开始,每次只能走左下或右下一格,直到走到最后一行,把沿途的走过的所有数字加起来。
如何能使这个和最大?

【问题复杂度分析】如果熟悉回溯法,就会立即发现这是一个动态的决策问题:每次两个选择----左下或右下。
但是如果选择用回溯法解决此问题,惯常的问题就是效率太低:一格n层的数字三角形的完整路线有2^n条,所以当n很大时完全不能靠此方法。

因此为了提高效率,需要把此问题抽象:把所有的位置(i,j)抽象为一个个不同的状态,然后定义状态(i,j)的指标函数d(i,j)为从格子(i,j)出发时能得到的最大的和(包括此格子本身)。在这个定义下,原问题的解是d(1,1)。

如下图:



 
【状态转移分析】从格子(i,j)出发有两种决策。若往左走,则走到(i+1,j)后续要求“从(i+1,j)出发后能得到的最大和“这一问题,即是d(i+1,j)。类似的,往右做之后要求解d(i,j+1)。由于这两个选择自由可选,所以,应该选择较大的。即得到了所谓的状态转移方程:

d(i,j) = a(i,j) + max { d(i+1, j), d(i, j+1)  }

最优子结构:如果往左走,最好的情况是(i,j)格子里面的值a(i,j) 与”从(i+1,j)出发后能得到的最大和"之和, 注意"最大"两个字,如果从(i,j)出发到底部这部分都不是最大的话,加上a(i,j)也必然不是最大的。这就是最优子结构。或描述全局最优解包含局部最优解。


【总结】动态规划的核心是状态和状态转移方程。

1.2 解决方法:记忆化搜索与递推


方法一:递归计算

代码如下:(注意边界)
int d(int i, int j)
{
return a[i][j] +( i == n ? 0 : d(i+1, j) >? d(i, j+1) ) ;
}

如此计算正确只是效率依然不高,问题在于重复计算。就是一些格子被两个父节点所共有,所以,在递归的时候,便会被重复计算。



方法二: 递推计算


代码如下:
(注意此时重复边界的处理)
int  i, j;
for (j=1; j<=n; j++)
d[n][j] = a[n][j] ;
for (i=n-1; i>=1; i--)
for (j=1; j<=i; j++)
{
d[i][j] = a [i][j] + d[i+1][j] >? d[i][j+1] ;
}

时间复杂度显然是O(n^2),
可以如此计算的原因在于:
i是逆序枚举的,因此在计算d[i] [j] 之前,他所需要的d[i+1][j] 和 d[i][j+1] 已经计算出来了。

提示:在多数情况下,可以采用递推法计算状态转移方程。递推的关键在于边界和计算顺序。多数情况下,递推法的时间复杂度是:状态转移方程X每个状态的决策数X决策时间。


方法三:记忆化搜索

程序分为两部分。首先用数组函数memset();将数组整体置为-1,然后写递归函数:
int d(int i, int j)
{
if(d[i][j >= 0) return d[i][j] ;
return d[i][j] = a[i][j] +( i == n ? 0 : d(i+1, j) >? d(i, j+1) ) ;
}

依然是递归函数,同时把计算结果存在数组d中。题目说各个数字均为非负数,因此如已经计算过某个d[i][j],那么期应该是非负数。
这样只需要把所有的数组元素初始化为负数,如-1,就可以知道是否计算过d[i][j].

注意:不要忘记把结果存在数组d[i][j]中。根绝c语言的”赋值语句本身有返回值“的规定,可以把保存d[i][j]的工作整合在函数的返回语句中。

上述的方法三称为记忆化,虽然不像地推算法那样显示的指明了计算的顺序,但是任然可以保证每个节点只访问了一次。

由于i和j都在1~n之间,所以所有的不同的节点之间一共有O(n^2)个。即是时间复杂度。

提示:可以用记忆化搜索的方法计算状态转移方程。采用记忆化搜索时,不必事先确定个状态的计算顺序,但需要记住每个状态是否计算过。


1.3程序实战练手

HDOJ--2084


未完待续...................
下一节:DAG上的(DP)

算法入门系列一--DP初步的更多相关文章

  1. 数据结构与算法入门系列教程-C#

    数据结构与算法入门系列教程 (一)为啥要学习数据结构与算法 曾经我也以为自己很牛逼,工作中同事也觉得我还可以,领导也看得起我,啥啥啥都好,就这样过了几年,忽然发现自己学新东西没劲.时代都变了,而我还只 ...

  2. 算法入门系列2:k近邻算法

    用官方的话来说,所谓K近邻算法(k-Nearest Neighbor,KNN),即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居), 这K个 ...

  3. 算法入门系列1:k-means

    k-means是一种无监督学习算法,用于聚类. 下图(来自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006910.html)展示了k-m ...

  4. 数据挖掘入门系列教程(二)之分类问题OneR算法

    数据挖掘入门系列教程(二)之分类问题OneR算法 数据挖掘入门系列博客:https://www.cnblogs.com/xiaohuiduan/category/1661541.html 项目地址:G ...

  5. 数据挖掘入门系列教程(三)之scikit-learn框架基本使用(以K近邻算法为例)

    数据挖掘入门系列教程(三)之scikit-learn框架基本使用(以K近邻算法为例) 简介 scikit-learn 估计器 加载数据集 进行fit训练 设置参数 预处理 流水线 结尾 数据挖掘入门系 ...

  6. 数据挖掘入门系列教程(四点五)之Apriori算法

    目录 数据挖掘入门系列教程(四点五)之Apriori算法 频繁(项集)数据的评判标准 Apriori 算法流程 结尾 数据挖掘入门系列教程(四点五)之Apriori算法 Apriori(先验)算法关联 ...

  7. 数据挖掘入门系列教程(五)之Apriori算法Python实现

    数据挖掘入门系列教程(五)之Apriori算法Python实现 加载数据集 获得训练集 频繁项的生成 生成规则 获得support 获得confidence 获得Lift 进行验证 总结 参考 数据挖 ...

  8. 前端学习 node 快速入门 系列 —— 初步认识 node

    其他章节请看: 前端学习 node 快速入门 系列 初步认识 node node 是什么 node(或者称node.js)是 javaScript(以下简称js) 运行时的一个环境.不是一门语言. 以 ...

  9. vue 快速入门 系列 —— 初步认识 vue

    其他章节请看: vue 快速入门 系列 初步认识 vue vue 是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架. 所谓渐进式,就是你可以一步一步.有阶段 ...

随机推荐

  1. POJ 1312 Numerically Speaking

    题意:a = 1, b = 2, ..., z = 26, aa = 27, ... 给字符串或者数字,输出对应的答案. 解法:类似26进制……但又不完全是……拿java大数模拟了一下…… 代码: i ...

  2. Oracle数据库启动时:ORA-00119: invalid specification for system parameter LOCAL_LISTENER; ORA-00132错误解决

    问题描述: 1. em打开中提示 https://localhost:1158/em/console/database/instance/repDown?target=orclweng&typ ...

  3. ajax-Ajax试题

    ylbtech-doc:ajax-Ajax试题 Ajax 1.A,Ajax试题返回顶部 001.{Ajax题目}使用Ajax可带来便捷有()(选择3项)      A)减轻服务器的负担      B) ...

  4. WCF扩展

    WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...

  5. jquery阻止冒泡事件:$('span').bind("click",function(event){event.stopPropagation();})(有用源)

    冒泡事件就是点击子节点,会向上触发父节点,祖先节点的点击事件. <body> <div id="content"> 外层div元素 <span> ...

  6. LyX转Word

    写毕业论文是一件非常繁锁的事情,一大堆的图片.公式都要往上贴,有时弄不好就把编号搞错了,有时可能没注意,一不小心字体格式.版面格式又全乱了.怎么办?--其实这只是在word环境下才会有的烦恼. 对于w ...

  7. Java-note-字符串连接

    String a="100"; int b=2; String c=a+b; then the answer is c=1002; + make the two sides bec ...

  8. Mac vim iterm2配色方案

    转自:http://www.vpsee.com/2013/09/use-the-solarized-color-theme-on-mac-os-x-terminal/ 相信长期浸泡在终端和代码的小伙伴 ...

  9. Jquery类级别与对象级别插件开发

    jQuery插件的开发包括两种: 一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法.jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级 ...

  10. 新建虚拟目录使用UNC共享文件夹(即:虚拟目录使用UNC共享文件夹)的方法 -摘自网络

    新建虚拟目录使用UNC共享文件夹(即:虚拟目录使用UNC共享文件夹)的方法1.UNC路径:\\192.168.1.2\test\,假设连接该UNC路径的用户名为:web,密码为:123 2.在原web ...