1015. 摘花生
Hello Kitty想摘点花生送给她喜欢的米老鼠。
她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。
地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。
Hello Kitty只能向东或向南走,不能向西或向北走。
问Hello Kitty最多能够摘到多少颗花生。
输入格式
第一行是一个整数 T T T,代表一共有多少组数据。
接下来是 T T T组数据。
每组数据的第一行是两个整数,分别代表花生苗的行数 R R R和列数 C C C。
每组数据的接下来 R R R行数据,从北向南依次描述每行花生苗的情况。每行数据有 C C C个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目 M M M。
输出格式
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
数据范围
1 ≤ T ≤ 100 , 1≤T≤100, 1≤T≤100,
1 ≤ R , C ≤ 100 , 1≤R,C≤100, 1≤R,C≤100,
0 ≤ M ≤ 1000 0≤M≤1000 0≤M≤1000
输入样例:
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
输出样例:
8
16
思路:
Hello Kitty
只能向东或向南走,不能向西或向北走,也即只能向右或者向下走。
这是一个典型的线性dp问题。
我们把走到一个点看做一个状态,对Hello Kitty
来说,走到一个点只有两种方式,一种是从上面下来走到该点,另一种是从左边过来走到该点。即要到达点 ( i , j ) (i,j) (i,j),要么是从 ( i − 1 , j ) (i−1,j) (i−1,j)走到 ( i , j ) (i,j) (i,j),要么是从点( i , j − 1 ) i,j−1) i,j−1)走到 ( i , j ) (i,j) (i,j)。
我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]来代表走到点 ( i , j ) (i,j) (i,j)一共摘到的花生。我们需要走到 ( n − 1 , m − 1 ) (n - 1,m - 1) (n−1,m−1),所以可以得到状态转移方程: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] ) , d p [ i ] [ j − 1 ] ) ) + a r r [ i ] [ j ] dp[i][j]=max(dp[i−1][j]),dp[i][j−1]))+arr[i][j] dp[i][j]=max(dp[i−1][j]),dp[i][j−1]))+arr[i][j]。根据转移方程,我们可以推出走到 ( n − 1 , m − 1 ) (n - 1,m - 1) (n−1,m−1)处摘到的最多花生。
Java代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt();
//共需要处理T组数据
while(T-- != 0){
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] arr = new int[n][m];
int[][] dp = new int[n][m];
//读入一组数据
for(int i = 0;i < n;i++){
for(int j = 0; j < m;j++){
arr[i][j] = scanner.nextInt();
}
}
//1. 初始化dp
dp[0][0] = arr[0][0];
//第一行的只能从左边过来
for(int j = 1;j < m;j++) dp[0][j] = dp[0][j - 1] + arr[0][j];
//第一列只能从上面下来
for(int i = 1;i < n;i++) dp[i][0] = dp[i - 1][0] + arr[i][0];
//2. 计算dp
for(int i = 1;i < n;i++){
for(int j = 1;j < m;j++){
dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1]) + arr[i][j];
}
}
System.out.println(dp[n- 1][m - 1]);
}
}
}