这次的题目是这样的:
假设有一个6*6的棋盘,每个格子里面有一个奖品(每个奖品的价值在100到1000之间),现在要求从左上角开始到右下角结束,每次只能往右或往下走一个格子,所经过的格子里的奖品归自己所有。问最多能收集价值多少的奖品。
最先看到这个问题的时候脑子里面的立马出现许多的脑洞:暴力、二叉树、图中的带权路径等等。但是想来想去没有想出个所以然来。偶然在一本算法书上看见了讲DP算法(动态规划)的部分,仔细一想,貌似能够用在这里的。
DP算法适用于前一步的决策影响后一步决策的问题中。本题蓝色方块的决策取决于其左边和上面的最优决策,因此,对于蓝色部分a[i][j]只需要取max{a[i-1][j],a[i][j-1]}+a[i][j];对于白色部分,只受左边或者上面的决策影响,因此对于横向的a[i][j]应该取a[i][j-1]+a[i][j],对于纵向的a[i][j]应该取a[i-1][j]+a[i][j]。其实DP能够解决的问题还有很多,我相信这也是一个特别有用的算法,强烈建议阅读学习使用。
tips:代码中涉及python中二维数组的初始化和赋值,可以用列表推导式初始化。
代码:
1 import random 2 count=0 3 a=[[0 for i in range(6)]for i in range(6)] 4 print("随机生成一个6*6的二维数组做为棋盘中的权值:") 5 for i in range(6): 6 for j in range(6): 7 a[i][j] = random.randint(100, 1000) 8 print('%2d'%a[i][j],end=" ") 9 count+=1 10 if count%6==0: 11 print("\n") 12 for i in range(1,6): 13 a[0][i]=a[0][i-1]+a[0][i] 14 a[i][0]=a[i-1][0]+a[i][0] 15 for i in range(1,6): 16 for j in range(1,6): 17 a[i][j]=max(a[i-1][j],a[i][j-1])+a[i][j] 18 print("变化后的数组:") 19 for i in range(6): 20 for j in range(6): 21 print('%2d'%a[i][j],end=" ") 22 count+=1 23 if count%6==0: 24 print("\n") 25 print("最终得最大值为%d" %a[5][5])
运行结果:
当然,在自己做出来之前,不免询问了一下我们的度娘,也得到了一种暴力解法,无奈用的递归解决的,太暴力太烧脑,想了好久都没想通,这里将原c++版的代码改写成了python的代码供大家学习思考。
#6*6的棋盘求最大路径 import random global count totalprice=0 tmp=0 count=0 a=[[0 for i in range(6)]for i in range(6)] b=[[0 for i in range(6)]for i in range(6)] next=[[1,0],[0,1]] def find(x, y): global totalprice global tmp totalprice+=a[x][y] if x==5 and y==5: if totalprice>tmp: tmp=totalprice return for k in range(2): tx=x+next[k][0] ty=y+next[k][1] if tx<0 or tx>5 or ty<0 or ty>5: continue if b[tx][ty]==0: b[tx][ty]=1 find(tx,ty) totalprice-=a[tx][ty] b[tx][ty]=0 return for i in range(6): for j in range(6): a[i][j] = random.randint(1, 100) print('%2d'%a[i][j],end=" ") count+=1 if count%6==0: print("\n") b[0][0]=1 find(0,0) print(tmp)