蓝桥--跳跃(模拟赛,简单dp做法)

题目描述

小蓝在一个 n 行 m 列的方格图中玩一个游戏。

开始时,小蓝站在方格图的左上角,即第 1 行第 1 列。

小蓝可以在方格图上走动,走动时,如果当前在第 r 行第 c 列,他不能走到行号比 r 小的行,也不能走到列号比 c 小的列。同时,他一步走的直线距离不超过 3。

例如,如果当前小蓝在第 3行第 5 列,他下一步可以走到第 3 行第 6 列、第 3 行第 7 列、第 3 行第 8列、第 4 行第 5 列、第 4 行第 6 列、第 4 行第 7 列、第 5 行第 5 列、第 5 行第 6 列、第 6 行第 5 列之一。

小蓝最终要走到第 n 行第 m 列。

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

小蓝希望,从第 1 行第 1列走到第 n 行第 m 列后,总的权值和最大。请问最大是多少?

输入描述

输入的第一行包含两个整数n,m,表示图的大小。

接下来 n 行,每行 m个整数,表示方格图中每个点的权值。

其中,1 <=n <= 100,-10^4 <=权值 <=10^4。

输出描述

输出一个整数,表示最大权值和。

输入输出样例

示例 1

输入

3 5
-4 -5 -10 -3 1
7 5 -9 3 -10
10 -2 6 -10 -4

输出

15

 解题思路

本题是模拟赛的一道dp题,要求小蓝从1行1列到n行m列后的最大总权值和。

那我们先来看小蓝每一步可以怎么走,因为一步走的直线距离不能超过3,如图所示:

有一个5行5列的图,小蓝站在(1,1)位置上,下一步可以走到的点就是蓝色部分,那么选择走到哪个点呢?因为题目要求总的权值和最大,所以我们就选权值最大的那个点作为下一个位置。这里我们已经知道了小蓝是怎么选择走到下一个位置的,那么问题来了,当小蓝走到(5,5)也就是出口的时候,怎么算总的权值呢?这里我们就要换个思路了,如下图:

 当小蓝站在(4,4)位置上时,可以从哪些点走到小蓝的位置?很明显蓝色部分就是可以走到小蓝的位置,和上面不同的是,这里我们选择权值最大的点来作为小蓝的上一个位置,以此类推,当小蓝走到(5,5)的时候dp[-1][-1]就是我们要的结果。

所以当前可确定状态转移方程为:

dp[i][j]+=max(dp[i][j-1],dp[i][j-2],dp[i][j-3],dp[i-1][j],dp[i-1][j-1],dp[i-1][j-2],dp[i-2][j],dp[i-2][j-1],dp[i-3][j])

但要注意的是,不是所有的位置都是可以从9个位置选择一个权值最大的作为上一位置的。比如小蓝站在(2,2)的位置,那么他的上一位置就只有从(1,1),(1,2),(2,1)三个选择权值最大的一个,所以我们还需要判断当前位置的上一位置是否还在图中,也就是有没有出边界。所以为了更好的判断,我们可以设一个列表来存储增量,通过遍历增量来判断上一位置的索引:

dirs=[(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(2,0),(2,1),(3,0)] #增量

我们通过当前位置和依次遍历增量来判断所有满足上一位置的点,如果这个点满足的话那么我们就把这个点的权值保存到一个列表result中,直到我们把所有满足上一位置的点的权值都保存到列表之后,我们加上最大的一个就行了。这时新的状态转移方程为:

dp[i][j]+=max(result)

当然如果当前位置是起始位置(0,0)时,这时候它就不能满足转移方程 ,所以这里我们还要加一个判断是不是在起始位置。

Code:

n,m=map(int,input().split())
dp=[]
for i in range(n):
  l=list(map(int,input().split()))
  dp.append(l) #接收数据
dirs=[(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(2,0),(2,1),(3,0)] #增量
for i in range(n):
  for j in range(m):
    result=[]
    for x,y in dirs: #根据当前位置和增量判断上一位置
      x1=i-x   #上一位置的横轴索引
      y1=j-y   #上一位置的纵轴索引
      if x1>=0 and x1<n and y1>=0 and y1<m: #判断上一位置是否在图中
        res.append(dp[x1][y1]) #在的话把权值添加进列表
    if i==0 and j==0: # 在(0,0)位置跳过
      continue
    else:
      dp[i][j]+=max(result)  #转移方程,加上最大的权值
print(dp[-1][-1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值