题目:
在一个 m*n 的棋盘的每一个格都放有一个礼物,每个礼物都有一定价值(大于 0)。从左上角开始拿礼物,每次向右或向下移动一格,直到右下角结束。给定一个棋盘,求拿到礼物的最大价值。例如,对于如下棋盘
1 10 3 8
12 2 9 6
5 7 4 11
3 7 16 5
礼物的最大价值为 1+12+5+7+7+16+5=53。
这个问题两种思路,一种是直接递归求解,另一种是动态规划,更优解肯定是动态规划,因为简单递归求解会产生很多重复计算
1. 递归求解
想计算到达右下角的最大路径,就要先算出到达上面的点的最大路径和左边的点的最大路径,然后去较大值加上5
而在求上面点的最大路径时又要先求出到达4这个点的最大路径,
同样在求到达16这个点的最大路径时也要先求出到达4这个点的最大路径,这样就重复计算了,这是这类递归问题的通病(斐波那契数列问题),解决办法就是将中间状态保存下来,避免重复计算。
2. 动态规划
也可以用优化过的递归实现动态规划的解法(即在递归方法中闯入一个保存中间状态的二维数组,不过需要额外的存储空间),当然也可用不用递归,我们说一下不用递归的解法。
我们按照二维数组的遍历顺序来看,即从上到下,从左至右,
对于最上面一行,只有从左至右的路劲;而对于最左边一列,只有从上至下的路径,
比如在遍历到3这个点时,我们要计算到达这个点的最大路径,要先求出子路径,而3的上面没有点,只有左面有,因此到达3的最大路径就是10的最大路径加3,这样第一行就都能求出来
再往下看,例如我们遍历到12这个点,它的左面没有点,因此最大路径就是上面的点的最大路径加12;
然后从12向右遍历到2这个点,此时2的左面的最大路径和上面的最大路径都已经计算出来的,因此2的最大路径也能计算出来,一次类推,最后所有的点的最大路径都能求出来;
总结一下:
递归与动态规划是从不同的角度求解问题,递归从最终要得到的结果触发,即从问题本身出发,要想得到问题的解,那么就要先求出子问题的解,依次递归下去;当子问题只有一个时递归是没什么问题的,但是对于斐波那契数列类的问题,子问题有两个甚至多个,而子问题右是子问题的子问题,这样就会产生大量重复计算,时间复杂度变大。
动态规划则是利用额外的存储空间保存子问题的解,从而避免对子问题的重复计算。