⭐问题详情:
❀给出一个数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
❀路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。(是指走到底部向左下走的总次数与向右下走的总次数相差不能超过 1。)
🥥例子1: 🥥例子2:
7 3
3 8 5 6
8 1 0 7 2 1
2 7 4 4 2 4 7 4
4 5 2 6 5 3 4 5 1 3
⭐输入
❤例子1:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
❤例子2:
3
5 6
7 2 1
2 4 7 4
3 4 5 1 3
⭐输出
❤例子1:27
❤例子2:23
❗❗❗为了便于理解,我决定先给题目降低难度,即把题目红色的那句话去掉。
于是,题目变成了:
给出一个数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
⭐现在我们的输出就变成了:
❤例子1:30
❤例子2:24
⭐详解1
❤例子2:
3
5 6
7 2 1
2 4 7 4
3 4 5 1 3
可以看出每个数只能和离它最近的下边的数或者离它最近的下边的数的右边的那个数
如上例子的第四行第一个数2,只能和下一行的第一个数3或第二个数4相加
如果我们从上往下走的话,不能很好地保证你所走的路的值相加一定是最大值。
如上例子所示,如果我们按每次都选择最大路走的话,如下所示:
3
5 6
7 2 1
2 4 7 4
3 4 5 1 3
如上所示,红色为我们所走过的路,它们的值相加为23,并不是最大。我们还得回去继续寻找其它路径,这带来了一定的麻烦。
3
5 6
7 2 1
2 4 7 4
3 4 5 1 3
如上所示,绿色为我们所走过的路,它们的值相加为24,此时才是最大值。
所以,我们采取了从下往上走的方法,这种方法可以更好的为我们找到最大值。
3
5 6
7 2 1
2 4 7 4(2在3和4中选一个最大,变为6;4在4和5中选一个最大,变为9,以此类推)
3 4 5 1 3
于是:
⚪第一轮:
3
5 6
7 2 1
6 9 12 7(这一行的各个元素各自加上下一行可以加的元素的最大值后每个位置的值)
3 4 5 1 3
⚪第二轮:
3
5 6
16 14 13(这一行的各个元素各自加上下一行可以加的元素的最大值后每个位置的值)
6 9 12 7
3 4 5 1 3
⚪第三轮:
3
21 20(这一行的各个元素各自加上下一行可以加的元素的最大值后每个位置的值)
16 14 13
6 9 12 7
3 4 5 1 3
⚪第四轮:
24(这一行的各个元素各自加上下一行可以加的元素的最大值后每个位置的值)
21 20
16 14 13
6 9 12 7
3 4 5 1 3
这样,我们就很好地找到最大路径的值啦!为24。
📕例子1是官方给的参考例子,可以尝试自己推一下!
⭐核心代码1
public class ch01 {
public static int operate(int n,int[][] D){
int i=n-2,j;
while(i>-1) {
j=0;
while (j < i+1) {
D[i][j] = Math.max(D[i + 1][j], D[i + 1][j + 1]) + D[i][j];
j++;
}
i--;
}
return D[0][0];
}
}
⭐详解2
❤例子2:
3
5 6
7 2 1
2 4 7 4
3 4 5 1 3
☞这次,题目加了要求,向左下走的次数与向右下走的次数相差不能超过 1。(这里值的是走到底部向左下走的次数与向右下走的次数相差不能超过 1)
☞如上例子所示,我们只能选择向左下走两次,向右下走两次,那么不管怎么样,他都会走到最后一行的中间位置,即最后一行5的位置(如果数字层数是偶数的话,则走到中间两个数的任一个位置)。
☞1的位置是可能经过路线,0则是不可能经过的路线。
1
1 1
1 1 1
0 1 1 0
0 0 1 0 0
☞所以我的思路是把那些不可能经过的路线且列在n/2(n是数字层数)之前的值改为0,因为列在n/2之后完全不会经过,所以不用管它。
☞于是,数字三角形变成了:
7
3 8
8 1 0
0 7 4 4
0 0 2 6 5
☞接下来就和详解1那里的一样了,可以自己推一下!
⭐核心代码2
public class ch02 {
public static int operate(int n,int[][]D){
int k=n/2-1;
int i,j;
if(n%2==0){
k-=1;
}
for(i=n-1;i>n/2;i--){
for(j=k;j>-1;j--){
D[i][j]=0;
}
k--;
}
i=n-2;
while(i>-1) {
j=0;
while (j < i+1&j<n/2) {
D[i][j] = Math.max(D[i + 1][j], D[i + 1][j + 1]) + D[i][j];
j++;
if(j==n/2){
D[i][j]+= D[i + 1][j];
}
}
i--;
}
return D[0][0];
}
}
⭐程序入口
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入数字层数:");
int n=sc.nextInt();
int i,j;
int[][] D=new int[n][n];
System.out.println("请输入每层数字的元素:");
for(i=0;i<n;i++){
for(j=0;j<i+1;j++){
D[i][j]=sc.nextInt();
}
}
//System.out.println(ch01.operate(n,D));
System.out.println(ch02.operate(n,D));
}
}
❗❗❗两个方法入口不能同时开启,因为我使用的是数据覆盖的方式,同时开启将导致结果不正确!
⭐运行结果