蓝桥杯算法训练-拿金币

题目要求:

资源限制

时间限制:1.0s   内存限制:256.0MB

问题描述

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

输入格式

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

输出格式

  最多能拿金币数量。

样例输入

3
1 3 3
2 2 2
3 1 2

样例输出

11

数据规模和约定

  n<=1000

分析:

这道题目给的标签是DP。

按照动态规划一般的解题步骤。

1.定义数组并确定其元素的含义。到底定义一维或是二维数组,这要看具体的题目再分析,但大多数的题目都是二维数组。

本题要求在一个n*n的数组中,找出一条线(这条线只能向右和下画)使其各元素的值加起来最大,拿到最多的金币。同样我们可以就利用题中的二维数组。(i,j)代表坐标,x[i][j]代表到达坐标(i,j)时的最优解,即拿到最多的金币。

2.找到数组元素之间的关系。比如 x[i][j] = x[i-1][j-1] + x[i-1][j] 这就是一种关系。类似总结规律。

这道题目共有三种关系:

当i,j 都等于0时,即在起始坐标。此时能拿到的最多金币就是它自身。

所以x[i][j] = x[i][j]

当i,j其中有一个为0时,即坐标为“数组的上左边缘”。在这种情况下到达该坐标只可能有一种情况,i为0:上个坐标(0,j-1)往右移动到达了该坐标(0,j),j为0:上个坐标(i-1,0)往下移动到达了该坐标(i,0)。由此我们便可得出结论:

j = 0:x[i][j] = x[i][j] + x[i - 1][j]

i = 0:x[i][j] = x[i][j] + x[i][j - 1]

这图应该能好理解一些:

 最后一种情况就是除去上面的两种情况了,i,j没有一个为0。题目可以知道每个点都是上个点向右或者向下移动后得到的。所以 x[i][j] = x[i][j] + x[i][j - 1] 或者 x[i][j] = x[i][j] + x[i - 1][j] 。所以我们只需要比较x[i][j - 1] 与x[i - 1][j] 的大小,取大的即可 。

所以x[i][j] = max(x[i][j - 1],x[i - 1][j])+ x[i][j]

最终我们输出右下角的那个点即可得到最终答案。

3.确定初始值。这道题的初始值很好分析,我们直接在第二步的分析中得到了初始值,即x[0][0],x[0][j],x[j][0]。

写代码:

ok,所有步骤分析完毕,接下来最简单的就是写代码了。

n = int(input())
x = [[0] * 0 for a in range(n)]
for i in range(n):
    line = input().split()
    for j in range(len(line)):
        x[i].append(int(line[j]))
for i in range(n):
    for j in range(n):
        #第一种关系
        if j== 0 and i==0:   
            x[i][j] = x[i][j]
        #第二种关系
        elif j == 0:
            x[i][j] = x[i][j] + x[i - 1][j]
        #第二种关系
        elif i == 0:
            x[i][j] = x[i][j] + x[i][j - 1]
        #第三种关系
        else:
            x[i][j] = max(x[i][j - 1],x[i - 1][j])+ x[i][j]
print(x[n-1][n-1])

不足之处,欢迎指正。

猜你喜欢

转载自blog.csdn.net/youngwyj/article/details/122194152