原题

小蓝在一个  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界 行  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_02 列的方格图中玩一个游戏。

开始时,小蓝站在方格图的左上角,即第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_03 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_03 列。

小蓝可以在方格图上走动,走动时,如果当前在第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_05 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_06 列,他不能走到行号比  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_05 小的行,也不能走到列号比  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_06 小的列。同时,他一步走的直线距离不超过  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_09

例如,如果当前小蓝在第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_09 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 列,他下一步可以走到第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_09 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_13 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_09 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_15 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_09 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_动态规划_17 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_18 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_18 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_13 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_18 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_15 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_13 列、第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_13 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_11 列之一。

小蓝最终要走到第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_02 列。

在图中,有的位置有奖励,走上去即可获得,有的位置有惩罚,走上去就要接受惩罚。奖励和惩罚最终抽象成一个权值,奖励为正,惩罚为负。

小蓝希望,从第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_03 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_03 列走到第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界 行第  蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_02 列后,总的权值和最大。请问最大是多少?

 蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_36


分析

本题考查动态规划算法,这里求n*m的数字矩阵中从第一个数按照题意的走法”走到“最后一个数,所经过的数字的最大和为多少?

首先,我们先理清楚”走法“,以下图的6行8列的数字矩阵为例,当前走到35的位置,则下一步走的位置在图中蓝色线经过的数字的位置,题意中的3步内是指向右走或向下走的距离不超过3(任意上下左右相邻的两个数距离为1)。

 蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_访问矩阵_37

所谓动态规划,常常需要根据前面步骤引起的状态变化更新后面的状态。这里我们需要逐一访问矩阵中每个数字,更新第一个数字到当前遍历的数字经过的路的最大权值,即所经过的数字的最大和。

解题的关键点在于:访问到当前数字,它可以从哪些数字走过来,从这些数字中的哪一个走过来会使和最大。还是以上述的6行8列的数字矩阵为例,若当前访问到数字45的位置,它可以从图中绿色线标出的数字的位置走过来。编程时需要注意数组越界问题,如到12、13、14的位置都只能从11的位置过来,到22的位置只能从11、12、21的位置走过来。

 蓝桥杯备战日志(Python)13-跳跃-(遍历、动态规划)_数组越界_38


源码

n,m = map(int,input().split())
grid = [ list(map(int,input().split())) for i in range(n)]

''' #输入:
3 5
-4 -5 -10 -3 1
7 5 -9 3 -10
10 -2 6 -10 -4
'''

def get_lasted_loc(i_now,j_now):
'''根据当前位置(i_now,j_now)获取可能的上一个位置'''
loc_l = []

for i in range(i_now-1,i_now-4,-1):
if i >= 0:
loc_l.append( (i,j_now) )
for j in range(j_now-1,j_now-4,-1):
if j >= 0:
loc_l.append( (i_now,j) )
for ij in [(i_now-1,j_now-1),(i_now-1,j_now-2),(i_now-2,j_now-1)]:
if ij[0] >= 0 and ij[1] >= 0:
loc_l.append(ij)
return loc_l

for i_now in range(n):
for j_now in range(m):
if i_now == 0 and j_now == 0:
continue
max_ = max(grid[i][j] for i,j in get_lasted_loc(i_now,j_now))
grid[i_now][j_now] += max_
print(grid[-1][-1])


上一篇:​​蓝桥杯备战日志(Python)12-递增序列&等差素数列-(”找规律“枚举&数论)​