该问题我使用了枚举法、备忘录法、动态规划法主要是对三种算法进行比较。
任何选择的问题,都可以通过穷举所有可能性,然后从中选择适合的项,这就是枚举法。枚举法是自顶向下,一般也会有递归公式。
设h为Triangle 的高度,v[i,j]为点(i,j)的数字值,sum[i,j]表示到从底到点(i,j)的所有路径中的最大和
运行结果
Time Limit Exceeded
根据题目给出的例题,GetSum共执行了31次,而点一共15个,所以有些点在计算sum时,进行了重复计算。
备忘录法就是对枚举法的改进,备忘录法也是自顶向下。
代码下载
http://download.csdn.net/detail/gykimo/4948780
将sum初始化为-1,获得某点的sum时,先判断sum是否小于0,如果小于0,说明还没有计算过该点的sum,如果大于等于0,则说明计算过该点的sum,可以直接使用sum。
运行结果
Accepted 768K 16MS
GetSum共执行了15次,而点一共15个,所以每个点只执行了一次。
这个问题有动态规划的特点
最优子结构
如果要求出(0,0)点的最大和,可以求出(1,0)和(1,1)的sum。而且这个时候(1,0)和(1,1)的sum是最大的,如果不是最大的,也就是存在另一个路径,使得(1,0)和(1,1)的sum更大,利用剪切法,这存在矛盾,所以(1,0)和(1,1)的sum是最大的。依此类推,该问题存在最优子结构。
递归解(也有叫状态转移公式的)
重叠子问题
根据备忘录法的分析,存在重叠子问题。
运行结果
Accepted 768K 16MS
具体详见枚举备忘录法最优规划对比
http://blog.csdn.net/gykimo/article/details/8457018
根据《枚举&备忘录法&最优规划》中,动态规划比备忘录法有更高的空间利用效率,我们分析当sum[i][j]计算后,v[i][j]其实根本没有存在的必要了,因为再也不会使用该数据了,那么,我们可以将sum[i][j]充当v[i][j],在初始状态下,sum[i][j]就是v[i][j]的值,当计算出来某点的路径和后,sum[i][j]就表示该点的路径和了。
运行结果
Accepted 740K 0MS
确实节省了部分空间,时间上也节省了不少
代码
北大ACM1163.DP.optimal.gykimo.cpp
http://download.csdn.net/detail/gykimo/4948959