蓝桥杯基础--枚举

目录

[1. 枚举](#1. 枚举)

[2. 解空间](#2. 解空间)

[3. 循环枚举解空间](#3. 循环枚举解空间)

[4. 例题](#4. 例题)

4.1特别数的和

4.2反倍数

4.3找到最多的数


在算法竞赛(如蓝桥杯)中,有一种最基础、最直观,但也极为实用的算法思想,那就是"枚举"。无论是刚刚入门的初学者还是经验丰富的算法高手,枚举都是必须熟练掌握的核心内功。今天我们就来深入探讨一下枚举的概念,以及它在蓝桥杯实战中的具体应用。

1. 枚举

枚举(Enumeration),在很多场合也被称为"穷举"或"暴力搜索"。它的核心逻辑非常直白:将问题可能出现的所有答案一一列举出来,然后根据题目给定的限制条件逐个进行检验。如果某个候选答案满足所有的条件,那么它就是我们要寻找的正确解。

枚举算法最大的优点在于逻辑清晰、实现简单且不易出错,只要时间允许,它能绝对保证找到正确的答案。在蓝桥杯比赛中,许多难度较低的题目完全可以直接通过枚举拿到满分;而在面对极其复杂的难题时,枚举往往也是一种非常有效的"保底"得分手段(即俗称的暴力部分分)。

2. 解空间

在动手编写枚举代码之前,我们必须先理清一个关键概念:解空间。

解空间指的是一个问题所有潜在可能解的集合。通俗来讲,就是正确答案可能隐藏的那个"大池子"。比如,题目要求寻找一个1到100之间的奇数,那么解空间就是1到100这100个整数。

精准地确定解空间是使用枚举算法的第一步,也是决定成败的一步。只有明确了解空间的范围和边界,我们才能评估需要枚举的次数,进而判断程序能否在比赛规定的时间限制内(通常是1秒钟左右)运行完毕。如果发现解空间过于庞大,我们可能就需要考虑剪枝优化或者直接寻找其他更高级的算法。

3. 循环枚举解空间

明确了解空间的范围之后,接下来的任务就是用代码将它完整地遍历一遍。在绝大多数编程语言中,我们通常通过"循环"结构来实现对解空间的枚举。

最常用的循环语句是 for 循环和 while 循环。对于一维的解空间(例如在一个简单数组中寻找目标值),一层 for 循环通常就足够了;对于二维或者多维的解空间(例如在棋盘或二维网格中寻找特定的图案组合),我们可能需要嵌套多层 for 循环。在循环体的内部,我们会配合 if 条件判断语句,来筛选出真正符合题目要求的那个解。

4. 例题

下面我们结合三道蓝桥杯的经典真题,来看看枚举算法在实际编程中是如何大显身手的。

4.1特别数的和

https://www.lanqiao.cn/problems/191/learning/?page=1&first_category_id=1&name=%E7%89%B9%E5%88%AB%E6%95%B0%E7%9A%84%E5%92%8C

思路解析: 这道题要求我们在1到n的范围内,找出所有各位数字中含有2、0、1、9这四个数字中任意一个的数,并计算它们的总和。这里的解空间非常明确,就是从1到n的所有整数。我们只需要用一层 for 循环枚举1到n的每一个数,再编写一个函数依次提取出该数字的每一位,检查是否含有这四个特定数字即可。

复制代码
#include <bits/stdc++.h>
using namespace std;

bool f(int i)
{
  while(i)
  {
    int x = i % 10;
    if(x == 2 || x == 0 || x == 1 || x == 9) return true;
    i /= 10;
  }
  return false;
}

int main()
{
  int n;
  cin >> n;
  int ans = 0;
  for(int i = 1; i <= n; i++)
  {
    if(f(i)) ans += i;
  }
  cout << ans << '\n';
  return 0;
}

4.2反倍数

https://www.lanqiao.cn/problems/152/learning/?page=1&first_category_id=1&name=%E5%8F%8D%E5%80%8D%E6%95%B0

思路解析: 题目要求在1到n的范围内,统计既不是a的倍数,也不是b的倍数,更不是c的倍数的数字的个数。解空间依然是1到n。我们直接用一个 for 循环遍历每一个数字,然后在循环内部利用取余操作符(%)来判断当前数字是否不能被a、b、c整除。如果条件成立,就将答案计数器加一。

复制代码
#include <bits/stdc++.h>
using namespace std;

int main()
{
  int n, a, b, c;
  cin >> n;
  cin >> a >> b >> c;
  int ans = 0;

  for(int i = 1; i <= n; i++)
  {
    if(i % a != 0 && i % b != 0 && i % c != 0) ans++;
  }
  cout << ans << '\n';
  return 0;
}

4.3找到最多的数

https://www.lanqiao.cn/problems/3227/learning/?page=1&first_category_id=1&problem_id=3227

思路解析: 这道题要求找出一个在矩阵中出现次数超过总元素数量一半的数字。解空间是矩阵中出现过的所有数字。我们可以巧妙地利用 C++ STL 中的 map 数据结构来记录每个数字出现的次数。这其实也是一种变相的枚举:先枚举输入的数据并完成统计,随后再枚举 map 里面存储的所有键值对,找出出现次数超过 n*m 一半的那个目标数字。

复制代码
#include <bits/stdc++.h>
using namespace std;
map<int, int> mp;

int main()
{
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int n, m;
  cin >> n >> m;

  for(int i = 1; i <= n * m; i++)
  {
    int x; cin >> x;
    mp[x]++;
  }

  for(const auto &[x, y] : mp)
  {
    if(2 * y > n * m) cout << x;
  }
  return 0;
}

本章完。

相关推荐
MORE_771 小时前
leecode100-跳跃游戏2-贪心算法
算法·游戏·贪心算法
j_xxx404_1 小时前
蓝桥杯基础--递归
数据结构·c++·算法·蓝桥杯·排序算法
森林里的程序猿猿2 小时前
导致内存泄漏的ThreadLocal详解
java·jvm·数据结构
tankeven2 小时前
HJ145 小红背单词
c++·算法
做怪小疯子2 小时前
Leetcode刷题——矩阵遍历
算法·leetcode·矩阵
羊小猪~~2 小时前
算法/力扣--链表经典题目
数据结构·后端·考研·算法·leetcode·链表·面试
mjhcsp2 小时前
C++ 信息论(Information Theory)完整万字教程
开发语言·c++
Alicx.2 小时前
每日一题-dfs
算法·蓝桥杯·深度优先
C++ 老炮儿的技术栈2 小时前
现代 C++(C++11 及以后)的移动语义
linux·c语言·开发语言·c++·github