刷题总结-拿金币
问题描述:有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入形式
第一行输入一个正整数N。
以下N行描述该方格。金币数保证是不超过1000的正整数。
数据规模和约定:N<=1000
样例
输入
3 1 3 3 2 2 2 3 1 2
输出
11
思路
1.
(1,1)
位置时,此时金币总数为1
2.
(1,2)
位置时,此时金币为1+3=4
3.
(1,3)
位置时,金币数量为4+3=7
**此时
dp
数组初状态已经得出4.
(2,1)
位置时,只能从(1,1)下移一格,金币为1+2=3
5.
(2,2)
位置,此位置可以由(1,2)
下移,也可(2,1)
右移,我们选择源头金币数量多的即 4+2=66.
(2,3)
位置同理,金币数量为7+2=97.
(3,1)
位置与(2,1)
位置同理,金币为68.
(3,2),(3,2)
重复5,6;最后得出金币数量最大为11
明显看出,在第一行初状态后,在其他行中从第二个元素开始就遵循左边和上边谁大选谁的规律
为了让第一列也遵循,我们可以将这个数组扩为
此时第一行与第一列也就遵循该规律
由此得出方程
dp[i][j] = dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + num[i][j];
经过观察,发现在使用
num[i][j]
时,后面的元素均未使用,故输入数据与行进可同时进行经过进一步观察(受大佬启发):此题的
dp
数组可用一维数组代替
c++
#include <iostream>
using namespace std;
int main()
{
int N;
scanf("%d",&N);
int num;
int dp [ 1001 ] = {0};
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
scanf("%d",&num);
dp[j] = dp[j]>dp[j-1]?(dp[j]+num):(dp[j-1]+num);
}
}
printf("%d",dp[ N ]);
return 0;
}
时间复杂度O(n^2)