题目描述
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
输入描述
输入的第一行包含一个整数 N (1 ≤ N ≤ 100),表示三角形的行数。
下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
输出描述
输出一个整数,表示答案。
输入输出样例
示例
输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出:
27
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
该题较经典动态分布算法题数字三角形有一个新的条件要求就是路径左右次数差不能大于 1,我们先来看一下如果没有这个要求的话该题该如何求解,知道经典解法之后就很容易就能接收这道题的解法了。
首先,拿这道题给的例子来分析。
对于这道题我们很容易想到使用一个二维矩阵来存储数据,这是可行的。若题目没有要求说向左下走的次数与向右下走的次数相差不能超过 1 的话,我们可以从矩阵的倒数第二行开始考虑,使用动态规划的思想进行求解。例如对于第 4 行 1 列的数据 2,他的前一个(从后往前考虑)数据可能是第 5 行 1 列的 4,也有可能是第 5 行 2 列的 5,那么我们可以判断得出,前一个数是 5 的时候和较大,故该路线的下一个目标是第 5 行 2 列的 5,所以我们可以把该矩阵的第 4 行 1 列的位置数值改为 7 (2 + 5),以此类推对矩阵的前 n - 1 行进行该操作,最后矩阵的第 1 行 1 列的位置数值即是路径的最大和。
对于这道题加入了一个新的条件,那么可以看到,也是一样拿这道题给的例子来说,若要求左右相差不能超过 1,则从矩阵最上面位置出发,不能到达的位置有下面这几个 (没有值的位置):
大家可以自行想一下,若左右次数相差不能超过 1 的话,对于这个五行的矩阵来说,需要往下走四步,那么可以有 1 左 3 右、2 左 2 右、2 右 2 左、3 左 1 右的四种走法,在这四种走法中只有中间两个方法是可行的,而通过中间两种走法走出来的路线所经过的位置是没有经过矩阵空白位置的,故这些位置可以考虑赋值为 0,如下图:
然后我们就可以按照上面讲的动态规划思想去解答这道题即可。该算法的 Java 代码实现如下:
import java.util.Scanner;
public class Main {
static int DP(int[][] arr) {
int N = arr.length;
for (int i = N - 2; i >= 0; i--) {
for (int j = 0; j <= i; j++) {
arr[i][j] += Math.max(arr[i + 1][j], arr[i + 1][j + 1]);
}
}
return arr[0][0];
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int[][] arr = new int[N][N];
int i, j, k, revise;
for (i = 0, revise = - (N / 2); i < N; i++, revise++) {//题目初始化
for (j = 0; j <= i; j++) {
arr[i][j] = scan.nextInt();
}
for (k = 0; k < revise; k++) {
arr[i][k] = 0;
arr[i][i - k] = 0;
}
}
System.out.println(DP(arr));
scan.close();
}
}