题目链接:http://oj.ecustacm.cn/problem.php?id=1526
题目分析
第一眼看到这道题,你可能就会想到dp,因为实在是太经典了!但是这道题加了个限制: 向左下走的次数与向右下走的次数相差不能超过1(注意:这个限制条件只需要结束时满足,不需要在途中满足)。
完全不会的话
完全不会的同学可以先学下没有限制下是如何解决的:
可以参考这篇文章:https://blog.csdn.net/zwhlxl/article/details/46225947(绝对不是因为我懒得写)
回到本题来
本题中,如果仍然采用dp[i][j]表示到达i行j列的收获的最大值,那么就无法满足限制条件。所以,仅仅靠 i 行 和 j列 这两个维度是无法满足题目要求的。那么该再加入什么样的维度呢?
根据限制条件,可以想到加入一个维度来表示 向左走的次数和向右走的次数的差值。
状态定义:
dp[i][j][k] :到达i行j列时,向右走的次数 — 向左走的次数=k的情况下获得的和的最大值
状态转移:
对于一个位置,还是两个方向转移过来:左上和右上,没有左上或者右上的可以看做有一个值为负无穷的左上或右上,这样就必定不会走那里,也就等效于没有,但是我们代码就变得好写了(不用判断是否有左上或右上)
dp[i][j][k]=max(dp[i-1][j][k-1],dp[i-1][j-1][k+1])+arr[i][j] #arr[i][j]为三角形中i行j列的值
初始化:
在这里,我们一开始就知道结果的状态只有dp[0][0][0]。即在最顶上,一步没走的情况下的最大和。
dp[0][0][0]=arr[0][0]
获取结果:
要得到最终答案,就从最后一行满足 限制条件 (-1<=k<=1)的里面去寻找一个最大值即可。
AC代码:
# 数据读取:
n=int(input())
arr=[]
INF=1e9 #定义一个比较大的值(要大于计算过程中可能涉及到的最大值),表示无穷
dp=[[[-INF]*105 for j in range(n)] for i in range(n)]
for i in range(n):
arr.append(list(map(int,input().split())))
# 初始化:
dp[0][0][0]=arr[0][0]
for i in range(1,n):
for j in range(i+1):
for k in range(-50,51):#左右两边之差不可能超过±50
#状态转移
dp[i][j][k]=max(dp[i-1][j][k-1],dp[i-1][j-1][k+1])+arr[i][j]
#获取结果:
ans=-INF
for j in range(n):
ans=max(ans,dp[n-1][j][-1],dp[n-1][j][0],dp[n-1][j][1])
print(round(ans))
jio得不错的记得点个赞哦(。・∀・)ノ゙