题目描述:
在一个 m*n 的棋盘中的每一个格都放一个礼物,每个礼物都有一定的价值(价值大于0).你可以从棋盘的左上角开始拿各种里的礼物,并每次向右或者向下移动一格,直到到达棋盘的右下角。给定一个棋盘及上面个的礼物,请计算你最多能拿走多少价值的礼物?
题目分析:
使用递归思路分析,定义f(i,j)表示到达坐标为(i,j)的格子能拿到礼物总和的最大值。则有两种可能的途径,从左边(i,j-1)到达(i,j),从上面(i-1,j)到达(i,j)。
f(i,j)=max(f(i,j-1)+f(i-1,j))+g(i,j) g(i,j)表示坐标为(i,j)的格子里礼物的价值
递归求解,会有大量的重复计算,通过递归分析,使用从下到上的循环求解(本题倒着分析,正着求解)
解法1:使用与原始数组相同大小的数组存储中间结果(中间变量:找相邻从上或从下最大的礼物价值)
1 | 11 | 14 | 22 |
13 | 15 | 24 | 30 |
18 | 25 | 29 | 41 |
21 | 32 | 48 | 53 |
1 import numpy as np
2 def getmaxGift(values,rows,cols):
3 midvars=np.zeros((4,4)) #使用一个二维矩阵存放中间变量
4 for r in range(rows):
5 for c in range(cols):
6 left = 0
7 up=0
8 if r>0:
9 up = midvars[(r-1)][c]
10 if c>0:
11 left = midvars[r][c-1]
12 midvars[r][c] = max(up,left)+values[r*cols+c]
13 print(midvars)
14 return midvars[rows-1][cols-1]
15 if __name__ == '__main__':
16 values=[1,10,3,8,12,2,9,6,5,7,4,11,3,7,16,5]
17 print(getmaxGift(values,4,4))
结果:
[[ 1. 11. 14. 22.]
[13. 15. 24. 30.]
[18. 25. 29. 41.]
[21. 32. 48. 53.]]
53.0
解法2:
找最大价值53,只和48,41有关,找48,只和32,29有关,所以设置一个和列数相同的一维数组,不断的更新一维数组,存储由上和左得到的当前最大值
1 def getmaxGift2(values,rows,cols):
2 vars=[0]*cols
3 for r in range(rows):
4 for c in range(cols):
5 left=0
6 up = 0
7 if r>0:
8 up=vars[c]
9 if c>0:
10 left=vars[c-1]
11 vars[c]= max(up,left)+values[r*cols+c]
12 print('每一轮vars的变化')
13 print(vars)
14 return vars[-1]
15 if __name__ == '__main__':
16 values=[1,10,3,8,12,2,9,6,5,7,4,11,3,7,16,5]
17 print(getmaxGift2(values,4,4))
结果:
note:
特殊值处理:在函数开始加上如下代码即可
1 if not values or rows<0 or cols<0:
2 return 0
参考:
1.何海涛. 剑指Offer.第2版[M]. 电子工业出版社, 2014.