爽歪歪666
不以物喜,不以己悲,努力才是永恒的主题。

题目描述:

在一个 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.

2.https://blog.csdn.net/dugudaibo/article/details/79678890

posted on 2020-04-15 12:32  爽歪歪666  阅读(518)  评论(0编辑  收藏  举报