蓝桥杯动态规划:数字三角形
这题是第十一届蓝桥杯省赛的试题H,当时比赛的时候自己也是菜鸟一枚,当然现在也还是…
下面是题目:
这是一个典型的动态规划算法题。
解题思路:
样例输入
5
7
8 1
2 7 4
先划分子问题。最终状态是到数字塔低端,所以我们自下而上逐层决策。对于倒数第二层8 1,8和1dou有可能走到,那么走到8或1的时候再向下走,我们肯定选择值最大的路径走,比如走到8,我们会选右下方的7,因为左下方的2比右下方的7小,1同理也会选7,因为7比4小。所以子问题解决了,我们可以合并最后一层和倒数第二层,直到将n层数塔问题变成二层数塔问题再变成一层数塔问题也就是答案了:
二层数塔
7
15 8
当得到最后一个子问题也就是二层数塔问题的时候答案就出来了,肯定选左下方的15,也就是最大值为7+15=22.这部分的算法就是如下代码,从倒数第二层开始,逐层合并,最后输出chs[0][0]就是答案了。
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j < i + 1; j++)
chs[i][j]+=Math.max(chs[i+1][j],chs[i+1][j+1]);
到这里我们只解决了寻找最大路径的值的问题,没有解决向左下方走和向右下方走的次数相差不能超过1的问题。
下面我们来解决它
思路:
先看下面两张图
以五层和六层数塔为例,想要向左下方走和向右下方走的次数相差不能超过1就不能走红线圈中的路径里。多画图就知道为什么了。
代码思路就是从键盘获取数塔到数组中后,把红圈对应的数组元素置为零就可以了。用for循环来赋值。红圈对应的数组的纵坐标大于n/2+1,横坐标除开大于当前横坐标i/2和小于当前横坐标i/2的就行了,也就是除了中间的都是要置为零的。
for (int i = n - 1; i > n / 2 + 1; i--)
for (int j = 0; j < i; j++) {
if(j<i/2||j>i/2)chs[i][j] = 0;
else continue;
}
我只简单实现,没有做代码简化,也没有测试很多用例,原因嘛,因为我懒。可能有错可能不够好,仅供参考。
下面是完整的代码:
static int chs[][];
public static void main(String[] args) {
M();
}
public static void M() {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
chs = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < i + 1; j++)
chs[i][j] = sc.nextInt();//从键盘获取数塔
sc.close();
for (int i = n - 1; i > n / 2 + 1; i--)
for (int j = 0; j < i; j++) {
if(j<i/2||j>i/2)chs[i][j] = 0;//把不能经过的路径置为零
else continue;//其余的不动
}
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j < i + 1; j++)
chs[i][j]+=Math.max(chs[i+1][j],chs[i+1][j+1]);//合并数塔,解决子问题
System.out.println("最大路径值为:" + chs[0][0]);//输出答案
}