1.题目
题目描述
设有 N × N N \times N N×N 的方格图 ( N ≤ 9 ) (N \le 9) (N≤9) ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0 0 0 。如下图所示:
A
0 0 0 0 0 0 0 0
0 0 13 0 0 6 0 0
0 0 0 0 7 0 0 0
0 0 0 14 0 0 0 0
0 21 0 0 0 4 0 0
0 0 15 0 0 0 0 0
0 0 0 0 0 0 0 0
B
某人从图的左上角的
A
A
A 点出发,可以向下行走,也可以向右走,直到到达右下角的
B
B
B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字
0
0
0 )。
此人从
A
A
A 点到
B
B
B 点共走两次,试找出
2
2
2 条这样的路径,使得取得的数之和最大。
输入格式
输入的第一行为一个整数 N N N (表示 N × N N \times N N×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 0 0 0 表示输入结束。
输出格式
只需输出一个整数,表示 2 2 2 条路径上取得的最大的和。
输入输出样例
输入 #1
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
输出 #1
67
2.思路
主要思路:动态规划。该问题可以转化为两个人分别从 A A A 点走各自的路径到 B B B 点,要求两人一路上取走的数值之和最大。
- 步骤一:定义动态规划数组
dp
的含义
定义状态规划数组dp
为一四维数组,即dp[i][j][k][l]
,表示第一个人走到点 ( i , j ) (i, j) (i,j) 及第二个人走到点 ( k , l ) (k, l) (k,l) 一路上取走的数值之和的最大值。 - 步骤二:定义状态转移方程
由于只能向下走和向右走,则dp[i][j][k][l]
的值与dp[i - 1][j][k - 1][l]、dp[i - 1][j][k][l - 1]、dp[i][j - 1][k - 1][l]
和dp[i][j - 1][k][l - 1]
的状态相关,即dp[i][j][k][l]
应取这四个状态中的最大值,再加上点 ( i , j ) (i, j) (i,j) 的值points[i][j]
和点 ( k , l ) (k, l) (k,l) 的值points[k][l]
,所以状态转移方程为 d p [ i ] [ j ] [ k ] [ l ] = max ( d p [ i − 1 ] [ j ] [ k − 1 ] [ l ] , d p [ i − 1 ] [ j ] [ k ] [ l − 1 ] , d p [ i ] [ j − 1 ] [ k − 1 ] [ l ] , d p [ i ] [ j − 1 ] [ k ] [ l − 1 ] ) + p o i n t s [ i ] [ j ] + p o i n t s [ k ] [ l ] dp[i][j][k][l] = \max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1], dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1]) + points[i][j] + points[k][l] dp[i][j][k][l]=max(dp[i−1][j][k−1][l],dp[i−1][j][k][l−1],dp[i][j−1][k−1][l],dp[i][j−1][k][l−1])+points[i][j]+points[k][l]但是,根据题目在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0 0 0 ),所以当 i = k i=k i=k 且 j = l j=l j=l 时,由于有一个人取走了该方格中的数,因此只加一次 p o i n t s [ i ] [ j ] points[i][j] points[i][j] 或 p o i n t s [ k ] [ l ] points[k][l] points[k][l] 。 - 步骤三:初始化过程转移的初始值
两人所走路径点的范围为 ( 1 , 1 ) (1,1) (1,1) 到 ( N , N ) (N,N) (N,N) ,则dp[i][0][k][0] = dp[i][0][0][l] = dp[0][j][k][0] = dp[0][j][0][l] = 0
。
3.代码
import java.util.Scanner;
/**
* @author xiaoyaosheny
* @discription 洛谷P1004 [NOIP2000 提高组] 方格取数
* @date 2021/7/9
*/
public class Main {
/**
* 程序入口
*
* @param args 输入参数
*/
public static void main(String[] args) {
// 获取输入参数
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt(); // N x N 方格图
int[][] points = new int[N + 1][N + 1];
int x = scanner.nextInt();
int y = scanner.nextInt();
int number = scanner.nextInt();
while (x != 0 && y != 0 && number != 0) {
points[x][y] = number;
x = scanner.nextInt();
y = scanner.nextInt();
number = scanner.nextInt();
}
// 动态规划
int[][][][] dp = new int[N + 1][N + 1][N + 1][N + 1];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
for (int k = 1; k <= N; k++) {
for (int l = 1; l <= N; l++) {
dp[i][j][k][l] = Math.max(Math.max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1]), Math.max(dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1])) + points[i][j] + points[k][l];
if (i == k && j == l)
dp[i][j][k][l] -= points[i][j];
}
}
}
}
// 输出结果
System.out.println(dp[N][N][N][N]);
}
}