数字三角形问题
数字三角形问题
上周没看题,一个月总有那么几天不方便,智商不在线,人也特别懒惰。恩,懂的人都会懂,哈哈~~废话少说~~~
记得这条题是作为动态规划初步引入的例题,不过因为工作后基本就没接触算法了,所以不太记得状态转移方程是怎样的。想了大半个小时,才想起解法(期间一直注意力不集中,风水说工作学习地方和床放一块是会有这种情况,参考故宫的前朝后寝,所以就容易摸鱼)
先简单介绍下题目意思(选自刘汝佳的《算法竞赛入门经典》(第2版)第9章的9.1.1)。
一、题目描述
有一个由非负整数组成的三角形,第一行只有一个数,除了最下面之外每个数的左下方和右下方各有一个数,如图所示:
从第一行的数开始,每次可以往左或往右走一格,直到走到最下行,把沿途经过的数全部加起来,如何走才能使得这个和尽量大?
二、题目分析
其实乍一看,大家都会觉得,我每次比较下一行是左边的格子大,还是右边格子大,选一个最大的格子走,最后就能获得最大和了。
这种想法是贪心算法,也就是,在对问题求解时,总是做出在当前看来是最好的选择,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。下面我举个例子来证明这种做法是错的:
按贪心思路去解,会获得红色箭头的路径,而这个和在最后不是最大的,而是最右边这条:1——》2——》1——》50
动态规划和贪心的区别可以参考这篇文章了解下:https://blog.csdn.net/sindyra/article/details/101098036
还是上面那个图,我加多了一行,下面左图是给出的数字三角形,右边是计算过程。下面分析下右边的计算过程是如何得出来的:
计算过程分析:
(1)第2行结果没什么好说的,就是第1行的1,分别加上第2行的数的和,所以会得出:4和3;
(2)第3行最左边和最右边的结果和也是没什么好说的,因为只能从对上的唯一一个选择计算过来。其实每一行最左边和最右边的计算和都是固定的,只能从上一行的最左边或最右边的分析结果加上当前数;回到第3行的第2个数也就是数字2,我们可以从对上一行的结果和:4 或 3 加上当前数,很明显 4 大于 3,肯定选择4+2,而不是3+2,所以会有6这个计算结果。
(3)然后对于每一行,当分析中间的数(去掉最左边和最右边的数,因为结果唯一),我们都比较上一行能选择过来的左边或者右边的哪个数大,再相加,一行行分析就会得出最后一行的结果值,从最后一行的结果值挑出最大的一个数,就是最终结果。
抽象归纳:
一开始,我觉得从最后一行的原始数字,一行行递推到第一行分析是比较贴合人的思考过程的,也就是从底向上计算,但貌似不好写状态转移表达式,于是强迫自己从顶向下思考。
定义一个dp(i,j),它表示格子(i,j)能得到的最大和,想想格子(i,j),它是从上一行的格子(i-1, j-1)或者格子(i-1, j)走过来的,我们肯定优先选择大的那个过来,然后加上格子(i,j)的数就是dp(i,j) 的值。
于是就有方程:
dp(i,j) = a(i,j) + max(dp(i-1,j-1), dp(i-1,j))
熟悉数组的都知道,下标处理不当会有越界问题,所以这个式子是要加判断的,还有预处理部分。
(1)dp(1,1) = 1, 因为前一行没数。dp(2,1),dp(2,2)套进去方程也是有问题的,因为 dp(i-1, j-1)的 变成 dp(1,0),是不对的。所以要加个限制:j-1>=1, i-1>=1
(2)对于每行最左边或最右边的数,也是有限制哦~~ 想想 dp(5,5) = a(5,5) + max(dp(4,4), dp(4,5)), 是错的!哪有dp(4,5)一说,另一个限制:
if (i = j) dp(i,j) = a(i,j) + dp(i-1,j-1)
所以状态转移方程前要加上这个判断,其他坑应该没了吧~~有的话,请细心的读者告诉我 ^_^
当整个三角形的数算过一遍之后,我们再对最后一行遍历,这个dp(n,1) ~ dp(n,n)(n=最后一行),最大的那个数就是结果了
书中的状态转移方程跟我想的大同小异:dp(i,j) = a(i,j) + max(dp(i+1,j) , dp(i+1, j+1)),表示从格子(i,j)出发时能得到的最大和,包括格子(i,j)本身的值。在这个状态下,原问题的解是dp(1,1),书中解析有点绕,我就不贴了,可以多百度看看
【我的是到达该格子,是以该格子为终点;他的是从,是以格子为起点】
不过想想还是比我想的好,因为没那么多人为边界去控制不可取的值。。。