题目描述
小蓝在一个 n 行 m 列的方格图中玩一个游戏。
开始时,小蓝站在方格图的左上角,即第 1 行第 1 列。
小蓝可以在方格图上走动,走动时,如果当前在第 r 行第 c 列,他不能走到行号比 r 小的行,也不能走到列号比 c 小的列。同时,他一步走的直线距离不超过 3。
例如,如果当前小蓝在第 3 行第 5 列,他下一步可以走到第 3 行第 6 列、第 3 行第 7 列、第 3 行第 8 列、第 4 行第 5 列、第 4 行第 6 列、第 4 行第 7 列、第 5 行第 5 列、第 5 行第 6 列、第 6 行第 5 列之一。
小蓝最终要走到第 n 行第 m 列。
在图中,有的位置有奖励,走上去即可获得,有的位置有惩罚,走上去就要接受惩罚。奖励和惩罚最终抽象成一个权值,奖励为正,惩罚为负。
小蓝希望,从第 1 行第 1 列走到第 n 行第 m 列后,总的权值和最大。请问最大是多少?
输入描述
输入的第一行包含两个整数 n, m 表示图的大小。
接下来 n 行,每行 m 个整数,表示方格图中每个点的权值。
其中,1 <= n <= 100,-10^4 <= 权值 <= 10^4。
输出描述
输出一个整数,表示最大权值和。
1. 想法
刚看到这道题的题目时都研究了半天,n行m列的方格,每个方格中都代表一个权值,每次最多走三格,从左上角向右向下向右下角进发。所以这道题很复杂的感觉,还得考虑每次走几个格,走哪儿能让权值最大。是最优解问题,首先需要一个二维数组,然后就不会了,只能求助于大佬的代码
2. 结果
输出15就对
3. 总结收获
看了别人的题解,获益颇深。
- 【逆向思考】不妨换个角度思考,我们既然要求走到(n,m)号格子的总的最大权值和,那么我们就应该想想,从哪些格子能够走到某目标格子。我们可以发现它还是一个三角形。
- 【找到规律】那么如果仔细观察就可以发现,所有可以一次跳跃到达该格子的格子都在该格子的左上部分区域,那么我们只需要将目标格子的左上部分区域的格子的F值(设F值为到达一个格子的最大总权值和)求出,即可将目标格子的F值确定下来。
- 【动态规划思想】只要我们按照从左往右、从上往下的顺序得到每个格子的F值,仅需要遍历一遍每个格子,当遍历到最后一个格子时,即可得到最后一个格子的F值。
最优化原理
一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优子结构性质
4.正确代码
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int[][] num = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
num[i][j] = scan.nextInt();
}
}
int[][] dp = new int[n][m];
//找到走到该点的所需的最大权值和(不包括该点的权值)
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j] = -100000;
//从该点往上
for (int k = i; k >= 0 && i-k<=3; k--) {
//从该点往左
for (int l = j; l >= 0 && (i-k+j-l<=3) ; l--) {
//1.不能原地踏步,所以不能与该点坐标一样
//2.步数要小于等于3
//3.要比当前的max大才更新max
dp[i][j] = Math.max(dp[i][j],dp[k][l] + num[i][j]);
}
}
if(i==0 && j==0){
dp[i][j] = num[i][j];
}
}
}
//输出最后一个点的最大权值和
System.out.println(dp[n-1][m-1]);
scan.close();
}
}
5. 错误代码
这个就不展示了😢。。。