问题描述
有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式
第一行输入一个正整数n。
以下n行描述该方格。金币数保证是不超过1000的正整数。
输出格式
最多能拿金币数量。
样例输入
3
1 3 3
2 2 2
3 1 2
样例输出
11
数据规模和约定
n<=1000
这是一道DP的入门题,如果知道DP(动态规划)算法的话,建议学习后再做会简单得多。
思路:
用一个二维数组map来存储带权图 ,map[i][j]表示i,j位置存放的金币
另建一个等大小的二维数组dp[i][j] 来存储当前位置取得的最大收益,dp[i][j]表示到达i,j位置后能取得的最大金币数
对于i,j>0的任意位置,总有dp[i][j] = max( dp[i][j-1] , dp[i-1][j] ) + map[i][j] 成立。
即:如果求dp[i][j]位置的最大金币数,只需要知道此位置上面的最大金币数与左边的最大金币数,取二者中的最大值 。
第一次我超内存了,原因是设置了一个max与每次求出的dp[i][j]比大小求最大值,当数据过大时会引起内存超限
解决办法就是不用设max值,dp[n-1][n-1]的值一定是最大值,换句话说,只要还能走,就还能再继续增加金币数,那么当不能走时,就是最大值了。
代码如下:
package DP;
import java.util.* ;
public class 拿金币 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in) ;
int n = sc.nextInt() ;
int[][] map = new int[n][n] ;
for( int i = 0 ; i < n ; i++ ){
for( int j = 0 ; j < n ; j++ ){
map[i][j] = sc.nextInt() ;
}
}
int[][] dp = new int[n][n] ;
dp[0][0] = map[0][0] ;
for( int i = 1 ; i < n ; i++ ){
dp[i][0] = dp[i-1][0] + map[i][0];
dp[0][i] = dp[0][i-1] + map[0][i] ;
}
for( int i = 1 ; i < n ; i++ ){
for( int j = 1 ; j < n ; j++ ){
dp[i][j] = Math.max(dp[i-1][j] ,dp[i][j-1]) + map[i][j] ;
}
}
System.out.println(dp[n-1][n-1]);
}
}
测评结果
评测点序号 | 评测结果 | 得分 | CPU使用 | 内存使用 | 下载评测数据 |
---|---|---|---|---|---|
1 | 正确 | 10.00 | 109ms | 22.39MB | 输入 输出 |
2 | 正确 | 10.00 | 218ms | 34.91MB | 输入 输出 |
3 | 正确 | 10.00 | 468ms | 91.96MB | 输入 输出 |
4 | 正确 | 10.00 | 390ms | 94.16MB | 输入 输出 |
5 | 正确 | 10.00 | 500ms | 94.50MB | 输入 输出 |
6 | 正确 | 10.00 | 562ms | 161.6MB | 输入 输出 |
7 | 正确 | 10.00 | 703ms | 169.6MB | 输入 输出 |
8 | 正确 | 10.00 | 765ms | 169.0MB | 输入 输出 |
9 | 正确 | 10.00 | 781ms | 173.2MB | 输入 输出 |
10 | 正确 | 10.00 | 796ms | 176.1MB | 输入 输出 |