砥砺前行,智慧点亮未来。
---同行者联盟
枚举法
枚举算法的思想:
枚举算法的核心思想是将问题的所有可能成为答案的解一一列举,然后根据问题给定的条件判断这些解是否合适。对于符合条件的解,保留;反之则舍弃。
枚举算法解题的基本思路:
-
确定枚举解的范围和判断条件: 在开始解题之前,需要明确枚举的解范围,并定义问题的判断条件。
-
选取合适的枚举方法: 选择适当的枚举方式进行逐一枚举,确保覆盖所有可能的解。避免遗漏任何真正的解,同时注意防止重复。
-
使用判断条件检验解: 在枚举过程中,应用事先确定的判断条件验证每个解的合法性,保留符合要求的解。
枚举算法的一般步骤:
-
确定范围和枚举方式: 根据题目确定枚举的范围,并选择合适的枚举方式。确保不遗漏任何真正的解,同时避免重复。
-
优化解空间: 查看是否存在优化的可能性,以缩小可能成为解的答案范围,提高解决问题的效率。
-
定义准确验证条件: 根据问题找到准确、易编码的验证条件,用于检验每个可能的解。
-
枚举和判断: 逐一枚举解并验证是否符合事先确定的条件,保留符合条件的解。
-
输出结果: 按照要求输出枚举过程中留下的符合条件的解。
简单型枚举
简单型枚举是通过简单的 for
循环嵌套解决的问题类型。
这种枚举方式没有特定的固定枚举模式,而且相对简单。只需按照题目的要求设计代码即可完成解题。
让我们通过一个示例题目来复习一下。
42 点问题
题目描述:
众所周知在扑克牌中,有一个老掉牙的游戏叫做24,选取4张牌进行加减乘除,看是否能得出24这个答案24这个答案24点,选取 4 张牌进行加减乘除,看是否能得出 24这个答案。
现在小蓝同学发明了一个新游戏,他从扑克牌中依次抽出 6 张牌,注意不是一次抽出,进行计算,看是否能够组成42点,满足输出YES,否则为NO;
最先抽出来的牌作为第一个操作数,抽出牌做第二个操作数,运算结果在当作第一个操作数,继续进行操作。
除不尽的情况保留整数。
请设计一个程序对该问题进行解答。
样例
输入 :K A Q 6 2 3
输出:YES
对于上面的样例我们进行了如下计算;
K*A=K 即 13*1=13
13/12=1 保留整数
1+6=7
7*2=14
14*3=42
题目解析:
这个题目我们可以依次枚举数字,然后在枚举数字间的符号即可。由于到结果之间进行了三步计算,所以我们这里需要进行一个递归操作,利用了上节课讲解的知识。
两重循环即可解决问题,伪代码如下:
op1 赋值为 第一个数
op(op[1] op[2])
{
for op in [+ - * /]
ans = 第一个操作数op1 操作 第二个操作数op2
如果是第六个操作数,就检验是否符合要要求 ==42?如果是就返回True
如果op(ans , op[3]) 返回 True,就返回True 因为找到了答案,否则就继续进行
没有找到答案返回False
}
但是思路很清晰,写起来却非常的复杂,我们使用我们讲过的 List 来优化这个枚举方式。
代码(Java语言):
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
// 存放我们获取的六张牌数值
static int[] a = new int[6];
static List<List<Integer>> ans = new ArrayList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 选了六张牌
for (int i = 0; i < 6; i++) {
// 初始化ans
ans.add(new ArrayList<>());
char c = in.next().charAt(0);
// 将字符设置为对应的数字
if (c == 'A') {
a[i] = 1;
} else if (c == 'J') {
a[i] = 11;
} else if (c == 'Q') {
a[i] = 12;
} else if (c == 'K') {
a[i] = 13;
} else {
a[i] = (c - '0');
}
}
// 先选中第一张牌,此时不进行任何处理
ans.get(0).add(a[0]);
// 接下来的每张牌中,和现有结果可以做+-*/运算
for (int i = 1; i <= 5; i++) {
for (int j = 0; j < ans.get(i - 1).size(); j++) {
// 基于上一轮的结果(存了+-*/的结果) 与当前抽到的牌做加法运算
ans.get(i).add(ans.get(i - 1).get(j) + a[i]);
// 基于上一轮的结果(存了+-*/的结果) 与当前抽到的牌做-运算
ans.get(i).add(ans.get(i - 1).get(j) - a[i]);
// 基于上一轮的结果(存了+-*/的结果) 与当前抽到的牌做*运算
ans.get(i).add(ans.get(i - 1).get(j) * a[i]);
// 基于上一轮的结果(存了+-*/的结果) 与当前抽到的牌做/运算
ans.get(i).add(ans.get(i - 1).get(j) / a[i]);
}
}
int flag = 0;
for (int i = 0; i < ans.get(5).size(); i++) {
//检查最后一次牌后的结果,如果有为42的,flag设置为1,代表符合42点要求
if (ans.get(5).get(i) == 42) {
flag = 1;
break;
}
}
if (flag == 1) {
System.out.println("YES");
}else {
System.out.println("NO");
}
}
}
学生分享视频
简单型枚举
招生:
现特邀P8大佬,哈工程研究生毕业者授数据结构与算法,带领大家学习300道经典算法题,有意向的可以沟通+V 17865578823