算法训练——拿金币

算法训练——02拿金币

问题描述:

有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。

输入格式:

第一行输入一个正整数n;

以下n行描述该方格。金币数保证是不超过1000的正整数。

输出格式:

最多能拿金币数量。

样例输入:

3

1 3 3

2 2 2

3 1 2

样例输出:

11

数据规模和约定:

n<=1000

附上代码:

#拿金币
n=int(input())
nums=[]
dp=[]

for i in range(n):
    #读取每一行的金币数目
    nums.append(list(map(int,input().split())))
for i in range(n):
    #创建一个n*n的全为0的二维数组
    dp.append([0]*n)

#将起始位置,即最左上角的金币值赋给dp[0][0]
#dp[i][j]代表移动至二维数组中第i行,第j列的位置时,此时存储累加的最大金币数目
#num[i][j]表示移动至某位置盒子里面拥有的金币数目
dp[0][0]=nums[0][0]

#确定初始范围
for i in range(1,n):
    #只能往下边走,表示最左边的一列的状态值,
    # 当前状态等于上一个状态(前面的路径上所有金币之和)加上现在格子里面的金币数
    dp[i][0]=dp[i-1][0]+nums[i][0]
    #只能往右边走,表示最上面一行当前状态的金币之和
    # (最大金币数——只有一条路,也不得不大)
    dp[0][i]=dp[0][i-1]+nums[0][i]

#状态转移函数
for i in range(1,n):
    for j in range(1,n):
        #最优子结构,表示当前路径金币之和的最大值
        dp[i][j]=max(dp[i-1][j],dp[i][j-1])+nums[i][j]

print(dp[n-1][n-1])

运行结果:

image-20220324171926991

有关拿金币问题的思考:

本题不是简单的比较当处于某位置时,比较其右边和下边的金币数值,然后选择金币数值大的那条路径,而是要求解一条最佳路径,使得这条路径上所获得的金币数量最多;这属于一个典型的动态规划问题,因此用dp算法进行求解。

DP算法核心思想:

确定二维数组大小为n*n,将某位置的金币数存入nums[i] [j]中,当移动至二维数组中第i行,第j列的位置时,可以将此时存储累加的最大金币数存入dp[i] [j]。

image-20220324165750222

边界

由于题目规定只能往右走或者往下走,在确定了从最左上角开始走时,我们可以令dp[0] [0]=nums[0] [0];这个时候就有两个特殊的边界情况需要处理,分别是第一行(dp[0] [i])和第一列(dp[i] [0])。

1、第一行(dp[0] [i])

因为题目规定,只能向下或者向右走,而第一行的格子,没有上一行,因此,只能说是由上一状态向右移动,这样一层一层的深入(个人感觉,有点套娃的感觉),我们可以发现,最上面的格子只能是横着走,即dp[0] [i]=dp[0] [i-1]+nums[0] [i],表示该种边界状态的最大金币数。(因为只有一条路,所以一定是最大)

2、第一列(dp[i] [0])

和上面的边界情况类似,如果出现在第一列,没有左边的列,只能由上一状态不断劲直向下,即dp[i] [0]=dp[i-1] [o]+num[i] [0]。

状态转移函数

如上图所示,有C->A和B->A两条路径都可以抵达A,为了获得最大金币数,我们可以通过判断B和C哪个存储的“路径金币之和”最大,我们用dp[i] [j]表示从初始位置到该位置([i] [j],第i行,第j列)存储累加的最大金币数。即dp[i] [j]=max(dp[i-1] [j],dpi] [j-1])+num[i] [j]。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周泡泡同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值