蓝桥杯之递归
1.数字三角形
题目描述
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和(路径上的每一步只可沿左斜线向下或右斜线向下走)。
输入描述
输入的第一行包含一个整数 N (1≤N≤100)N (1≤N≤100),表示三角形的行数。
下面的 NN 行给出数字三角形。数字三角形上的数都是 00 至 9999 之间的整数。
输出描述
输出一个整数,表示答案。
输入输出样例
示例
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30
动态规划解题思路
看到“三角形最大路径和”问题,直接想到“动态规划”
动态规划的核心思想:把原问题分解为相对简单的子问题,通过求解子问题的最优解来构建原问题的最优解。
动态规划的状态转移方程:dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + a[i][j]
利用动态规划求最大路径和的思路:从三角形的倒数第二行开始,自底向上逐层更新每个位置的最大路径和。
解题步骤模板:
for (int i = n - 1; i > 0; i--) {for (int j = 1; j <= i; j++) {if (a[i + 1][j] >= a[i + 1][j + 1]) {a[i][j] += a[i + 1][j];} else {a[i][j] += a[i + 1][j + 1];}}
}
System.out.println(a[1][1]);
示例代码模板:
import java.util.Scanner;public class Main {public static void main(String args[]) {Scanner sc = new Scanner(System.in);// 获取行数int n = sc.nextInt();// 创建二维数组存储三角形int[][] a = new int[n + 1][n + 1];// 填充二维数组for (int i = 1; i <= n; i++) {for (int j = 1; j <= i; j++) {a[i][j] = sc.nextInt();}}// 动态规划填充数组for (int i = n - 1; i > 0; i--) {for (int j = 1; j <= i; j++) {if (a[i + 1][j] >= a[i + 1][j + 1]) {a[i][j] += a[i + 1][j];} else {a[i][j] += a[i + 1][j + 1];}}}// 输出结果System.out.println(a[1][1]);sc.close();}
}
思维导图:
训练方法:
按照这个模板,先通过小规模示例数据测试,理解每个步骤的作用。然后尝试自己编写代码实现,确保理解每一步的逻辑。最后用大规模数据进行测试,观察性能表现,理解动态规划相比递归的优势。
2. 42点问题
题目描述
请你设计一个程序对该问题进行解答。
众所周知在扑克牌中,有一个老掉牙的游戏叫做 2424 点,选取 44 张牌进行加减乘除,看是否能得出 2424 这个答案。
现在小蓝同学发明了一个新游戏,他从扑克牌中依次抽出6张牌,注意不是一次抽出,进行计算,看是否能够组成 4242 点,满足输出 YES
,反之输出 NO
。
最先抽出来的牌作为第一个操作数,抽出牌做第二个操作数,运算结果再当作第一个操作数,继续进行操作。
注:除不尽的情况保留整数,而且扑克牌的四张 1010 都丢了,不会出现 1010,1和A都可能出现并表示1。
请设计一个程序对该问题进行解答。
输入描述
输出仅一行包含 66 个字符。
保证字符 ∈∈ 1 2 3 4 5 6 7 8 9 J Q K A
。
输出描述
若给出到字符能够组成 4242 点 , 满足输出 YES
,反之输出 NO
。
输入输出样例
示例
输入
K A Q 6 2 3
输出
YES
样例说明
- K×A=KK×A=K 即 13×1=1313×1=13
- 13/12=113/12=1 保留整数
- 1+6=71+6=7
- 7∗2=147∗2=14
- 14∗3=4214∗3=42
二维Vector逐层运算解题思路
看到“多步骤数学运算问题”或者“24点”游戏类问题,直接想到“逐层穷举所有可能”
二维Vector存储的核心思想:利用逐层运算,穷举所有可能的运算组合。
逐层运算的公式:当前层结果 = 前一层结果 ±/*// 当前数字
(注意:这里需要考虑所有运算的合法性,比如除数不能为零)
利用二维Vector逐层运算的思路:从初始值开始,逐层应用所有可能的运算,存储每一步的结果,直到达到目标层或满足某种终止条件。
解题步骤模板:
// 定义一个二维 Vector,用于存储每一步的计算结果
Vector<Vector<Integer>> ans = new Vector<Vector<Integer>>();// 初始化第一个元素,表示初始状态
ans.addElement(new Vector<Integer>());
ans.get(0).addElement(a[0]); // 假设 a 是一个已定义的数组,这里添加初始值// 从第1层到第n层,逐层计算可能的运算结果
for (int i = 1; i <= n; i++) {// 为当前层创建一个新的 Vectorans.addElement(new Vector<Integer>());// 遍历前一层的所有元素for (int j = 0; j < ans.get(i - 1).size(); j++) {// 对当前元素进行加、减、乘、除四种运算,并将结果添加到当前层ans.get(i).addElement(ans.get(i - 1).get(j) + a[i]); // 加法ans.get(i).addElement(ans.get(i - 1).get(j) - a[i]); // 减法ans.get(i).addElement(ans.get(i - 1).get(j) * a[i]); // 乘法ans.get(i).addElement(ans.get(i - 1).get(j) / a[i]); // 除法(注意:这里没有处理除数为0的情况)}
}
示例代码模板:
import java.util.Vector;public class Main {public static void main(String[] args) {// 定义一个二维 Vector,用于存储每一步的计算结果Vector<Vector<Integer>> ans = new Vector<Vector<Integer>>();// 初始化一个数组,表示需要操作的数字int[] a = { 2, 3, 4, 5, 6 };// 初始化第一个元素,表示初始状态ans.addElement(new Vector<Integer>());ans.get(0).addElement(a[0]); // 将初始值添加到第0层// 从第1层到第4层,逐层计算可能的运算结果for (int i = 1; i <= 4; i++) {// 为当前层创建一个新的 Vectorans.addElement(new Vector<Integer>());// 遍历前一层的所有元素for (int j = 0; j < ans.get(i - 1).size(); j++) {// 对当前元素进行加、减、乘、除四种运算ans.get(i).addElement(ans.get(i - 1).get(j) + a[i]); // 加法ans.get(i).addElement(ans.get(i - 1).get(j) - a[i]); // 减法ans.get(i).addElement(ans.get(i - 1).get(j] * a[i]; // 乘法ans.get(i).addElement(ans.get(i - 1).get(j] / a[i]); // 除法(注意:这里没有处理除数为0的情况)}}// 打印结果(这里可以选择最后一层的所有可能结果)System.out.println("Final results for the 5th step:");for (int num : ans.get(4)) {System.out.println(num);}}
}
思维导图:
训练方法:
-
先理解二维
Vector
的结构和用途,确保能够正确初始化和操作Vector
。 -
找一个简单的例子,比如
a = {2, 3}
, 手动计算可能的运算结果,然后用代码验证。 -
再尝试用代码实现一个复杂一点的例子,比如
a = {2, 3, 4}
, 观察输出结果是否符合预期。 -
考虑特殊情况,如除数为零的情况,添加相应的错误处理代码。
-
优化代码,避免重复计算,提高效率。
自学蓝桥杯笔记,希望我们可以一起学习!