DP(dynamic programming)
2018-08-06 本文已影响0人
小小少年Boy
以数字三角形为例:给出一个数字三角形,从顶部到底部有很多路径,求路径最大和。
如:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
源码
朴素DFS的想法就是从(0,0)开始求下一步(向下或者右下)的最大值加上当前点的值
//表示从第x行,第y个数往下走可以得到的最大价值和,dfs(0,0)即为本题解。
int dfs(int x,int y)
{
//递归出口
if(x > numCount - 1)
return 0;
//对于当前(x,y),取往下或者右下最大的,如此类推,(0,0)开始递归得到结果
return max(dfs(x+1,y),dfs(x+1,y+1)) + num[x][y];
以看出朴素DFS有大量的重复计算,比如对于中间的一点,他既是某一点的下又是另一点的右下
记忆化DFS就是把上面DFS的结果保存起来,要用的时候直接使,不需要再来一次递归:
//result数组保存中间结果
int dfs(int x,int y)
{
if(x > numCount - 1)
return 0;
//如果算过,直接取
if(result[x][y] != -1)
return result[x][y];
return result[x][y] = max(dfs(x+1,y),dfs(x+1,y+1)) + num[x][y];
综上,朴素DFS和记忆化DFS都是基于递归思想计算,而利用递归的条件有两个:
一是可以把待解决问题转化成一个新问题,而这个新问题的解决方法不变,但是问题规模在减小;
二是要有递归出口。
比如这里我们通过dfs(x+1,y)和dfs(x+1,y+1)去求(x,y),x大于行数的时候退出。
DP动态规划直接用数组保存状态,在状态和状态之间实现转移。
//numCount即数组三角形的行数
for(int i = numCount - 1; i >= 0; i--)
for(int j = 0;j <= i; j++)
result[i][j] = max(result[i+1][j],result[i+1][j+1]) + num[i][j];
???有问题
result数组空间比三角形大1,全初始化为0,Dp的计算过程是先算三角形的最后一行result[numCount-1][j],result[i+1][j]从实际意义讲不存在,这里等于1,所以这一行计算结果都是本身,然后算上一行直到(0,0),得到问题最终解。
可以看出记忆化DFS和DP动态规划都保存了中间结果,不同的是两者的想法正好是反的,DP从下往上算,记忆化DFS因为是递归从上往下算。