矩阵取数
(本文仅为笔者的个人学习笔记,如有不当之处恳请各位读者指正)
问题描述:
7 | 3 | 4 | 1 | 5 |
5 | 2 | 6 | 9 | 2 |
1 | 3 | 7 | 0 | 8 |
4 | 1 | 5 | 9 | 6 |
8 | 3 | 2 | 1 | 4 |
对于此类问题我们可以采用动态规划的思想,我们设矩阵dp[i][j]表示从第i行第j列出发到右下角所经过的权值和最大。初始时(添加第6行和第6列的0元素辅助):
7 | 3 | 4 | 1 | 5 | 0 |
5 | 2 | 6 | 9 | 2 | 0 |
1 | 3 | 7 | 0 | 8 | 0 |
4 | 1 | 5 | 9 | 6 | 0 |
8 | 3 | 2 | 1 | 4 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
首先考虑问题的最小规模,即矩阵只有一个元素,则权值直接是这个格子中的数。然后再将规模逐渐增大:当矩阵中有两个数时(右下角的两个数):
0 | |||||
0 | |||||
0 | |||||
0 | |||||
1 | 4 | 0 | |||
0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||
0 | |||||
0 | |||||
0 | |||||
2 | 5 | 4 | 0 | ||
0 | 0 | 0 | 0 | 0 | 0 |
同理第5行3列向下2+0,向右2+5,取最大值,对后续添加的元素依次进行这样的更新
0 | |||||
0 | |||||
0 | |||||
6 | 0 | ||||
18 | 10 | 7 | 5 | 4 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
对与第4行5列元素向右没有元素6+0,向下6+4,取最大值:
0 | |||||
0 | |||||
0 | |||||
9 | 10 | 0 | |||
18 | 10 | 7 | 5 | 4 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
0 | |||||
0 | |||||
0 | |||||
19 | 10 | 0 | |||
18 | 10 | 7 | 5 | 4 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
51 | 44 | 41 | 30 | 25 | 0 |
44 | 39 | 37 | 29 | 20 | 0 |
35 | 34 | 31 | 19 | 18 | 0 |
29 | 25 | 24 | 19 | 10 | 0 |
18 | 10 | 7 | 5 | 4 | 0 |
0 | 0 | 0 | 0 | 0 | 0 |
最后dp[1][1]即从左上角(1行1列)到右下角所经过的权值和的最大值。
import java.util.Scanner;
public class Main {
private static int[][] dp;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//矩阵行数
int m = sc.nextInt();//矩阵列数
dp = new int[n + 2][m + 2];//多开2行2列:0行和0列不用,n+1行的所有元素为0,n+1列的所有元素为0辅助用
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = sc.nextInt();//录入矩阵的值
}
}
//从右下角向左上角刷表
for (int i = n; i >= 1; i--) {
for (int j = m; j >= 1; j--) {
dp[i][j] += Math.max(dp[i][j + 1], dp[i + 1][j]);//状态迁移方程
}
}
System.out.println(dp[1][1]);
}
}
注:用不用0行0列无所谓(用即输出dp[0][0])。但一定要多加一行和一列的0元素,否则在刷新最后一行
或最后一列时会出现数组越界错误。