重点全在注释中
import java.util.Scanner;
/**
* @DATE: 2022/12/16
* 7
* 3 8
* 8 1 0
* 2 7 4 4
* 4 5 2 6 5
* 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。
* 对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到 最大的和。
* 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
* 此外, 向左下走的次数与向右下走的次数相差不能超过 1。
* 输入描述:
* 输入的第一行包含一个整数 N(1≤N≤100),表示三角形的行数。
* 下面的 N 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
* 输入样例:
* 5
* 7
* 3 8
* 8 1 0
* 2 7 4 4
* 4 5 2 6 5
*/
public class Q3Main {
/**
* 考点:动态规划
* 收获:定义对象数组,必须对经行初始化,否则都是null
*/
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//输入行数
int row = scan.nextInt();
//自定义的数据结构,因为下标为0不存值,所以row+1,注意Java默认会初始化都是0
Q3Node[][] data = new Q3Node[row + 1][row + 1];
//重点:初始化数组对象,如果没有这个初始化则data中的元素都是null
for (int i = 0; i <= row; i++) {
for (int j = 0; j <= row; j++) {
data[i][j] = new Q3Node();
}
}
//初始化数据
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= i; j++) {
data[i][j].value = scan.nextLong();
}
}
//动态规划,从第二行开始
for (int i = 2; i <= row; i++) {
//每一列都要遍历
for (int j = 1; j <= i; j++) {
//此处是从下往上找,选择value大的
if (data[i - 1][j - 1].value > data[i - 1][j].value) {
//向右走
//此时value存的就是,当前点能取到的最大值了
data[i][j].value += data[i - 1][j - 1].value;
data[i][j].left = data[i - 1][j - 1].left;
//向右的次数加一
data[i][j].right = data[i - 1][j - 1].right + 1;
} else {
//向左走
data[i][j].value += data[i - 1][j].value;
data[i][j].left = data[i - 1][j].left + 1;
data[i][j].right = data[i - 1][j].right;
}
}
}
long result = 0;
//疑问:如果第n层的l-r都大于1,怎么办?
//解答:底层节点中满足左右次数差小于1的节点必存在(可以自行画图模拟),所以只需要找其中最大的就可以。
//最终结果就在row行,找出row行满足左右次数差小于等于1的结果
for (int i = 1; i <= row; i++) {
//如果左右次数差小于等于1则满足条件,取其中最大的
if (Math.abs(data[row][i].right - data[row][i].left) <= 1) {
result = Math.max(result, data[row][i].value);
}
}
System.out.println(result);
}
private static class Q3Node {
/**
* 当前节点值,可能是初始值,可能是到达当前节点的最大值
*/
long value = 0;
/**
* 到达当前节点,向右边走了多少次
*/
long right = 0;
/**
* 到达当前节点,向左边走了多少次
*/
long left = 0;
}
}