题目要求:
资源限制
时间限制: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])
不足之处,欢迎指正。