分类->蓝桥杯JAVA练习->真题
题目 2584: 蓝桥杯2020年第十一届省赛真题-数字三角形
解题思路:
这道题是标准的动态规划类型题目,由传统的“数字三角形”改编的,加了一个条件“向左下走的次数与向右下走的次数相差不能超过 1”
方法上我参考了c323u2bdf的https://blog.csdn.net/qq_60212533/article/details/127138546
可以从上至下思考,也可以从下至上,这里将从上至下的方法
首先通过一个二维数组 a[][] 存储数字三角形
然后再用一个二维数组存储 amax[][] 每个数字的路径最大和
① 从第一行第一个开始分析,以下图为例:
到7的最大路径就是它本身,因此amax[0][0]=a[0][0]
② 然后看最左边这一列,它比较特殊,以下图为例:
3,8,2的上一个路径只能是上一行同列的位置,把斜着的图(左图)换成数组表示(右图)更清晰
也就是说,当列(j)为0(第一列)时,amax[i][j] = a[i][j] +amax[i-1][j]
③ 再看其他数字,以下图为例:
每个数字可以是其上一行对应列或者上一行左侧一列的分支,因此他的最大路径应该是这两个数中较大的那个分支走下来的
amax[i][j]=Math.max(a[i][j]+amax[i-1][j], a[i][j]+amax[i-1][j-1])
④ 综上所述,我们得到了方程,其代码形式如下:
amax[0][0]=a[0][0]; //首行首列元素的最大路径长度为其自身
for(int i=1;i<n;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0) //左侧的列特殊处理,只能是上一行对应列的分支
{
amax[i][j]=a[i][j]+amax[i-1][j];
}
else //其他列则可能是上一行对应列或者上一行左侧的列的分支
{
amax[i][j]=Math.max(a[i][j]+amax[i-1][j], a[i][j]+amax[i-1][j-1]);
}
}
}
⑤ 输出最大路径
这里我们需要注意前面提到的本题的附加条件“向左下走的次数与向右下走的次数相差不能超过 1”,这也就意味着最后一步总是集中于最后一行的中间,不明白的同学可以看下图:
根据奇数行和偶数行要分别讨论:
当为奇数行的时候,最后一步必定是最后一行的中心位置,只有这样才能保证“向左下走的次数与向右下走的次数相差不能超过 1”
而当三角形为偶数行的时候,最后一步就可能是中间两个数其中的一个,因为要最大值,所以输出二者之间大的那个
代码形式如下:
if(n%2==0)
{
System.out.print(Math.max(amax[n-1][n/2],amax[n-1][n/2-1]));
}
else
{
System.out.print(amax[n-1][n/2]);
}
整体代码如下所示:
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner sca=new Scanner(System.in);
int n= sca.nextInt();
int a[][]=new int[n][n];
for(int i=0;i<n;i++)
{
for(int j=0;j<=i;j++)
{
a[i][j]=sca.nextInt();
}
}
int amax[][]=new int[n][n];
amax[0][0]=a[0][0]; //首行首列元素的最大路径长度为其自身
for(int i=1;i<n;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0) //左侧的列特殊处理,只能是上一行对应列的分支
{
amax[i][j]=a[i][j]+amax[i-1][j];
}
else //其他列则可能是上一行对应列或者上一行左侧的列的分支
{
amax[i][j]=Math.max(a[i][j]+amax[i-1][j], a[i][j]+amax[i-1][j-1]);
}
}
}
if(n%2==0)
{
System.out.print(Math.max(amax[n-1][n/2],amax[n-1][n/2-1]));
}
else
{
System.out.print(amax[n-1][n/2]);
}
}
}
总结:
对于动态规划类的问题,关键在于状态转移方程,从一些已确定的边界着手推导结果