0
点赞
收藏
分享

微信扫一扫

信息学集训 | 13 枚举算法理论与实战

水墨_青花 2022-11-15 阅读 52


导读

信息学能够有助于孩子未来工作发展,提升孩子的综合能力。


这一节课我们开始学习枚举算法,了解枚举算法的思想,并通过一些题目来熟练掌握枚举算法。


1 看个例子

我们首先来看一个例子。


信息学课上一共有6名同学,老师让同学们两个人一组,分成三组,老师让小明把所有的情况写出来。



小明给6位同学编号1-6,那么就能分为如下几种情况:


1-2 3-4 5-6
1-2 3-5 4-6
1-2 3-6 4-5
1-3 2-4 5-6
1-3 2-5 4-6
1-3 2-6 4-5
1-4 2-3 5-6
1-4 2-5 3-6
1-4 2-6 3-5
1-5 2-3 4-6
1-5 2-4 3-6
1-5 2-6 3-4
1-6 2-3 4-5
1-6 2-4 3-5
1-6 2-5 3-4


上面这种做法,就是将所有的情况全部都列举出来。这就是我们今天要讲的枚举算法。

2 枚举算法理论

让我们先来看一下枚举算法的理论吧!

1 枚举介绍

首先我们来了解一下枚举算法。枚举算法是我们在日常中使用到的最多的一个算法,它的核心思想就是列举所有的可能性。


1、枚举算法的定义


在进行归纳推理时,如果逐个考察了某类事件的所有可能情况,因而得出一般结论,那么该结论是可靠的,这种归纳方法叫做枚举法。也叫穷举法


2、枚举类型


在C++中提供了enum类型类型,用于枚举所有的值,用法如下:


enum 枚举名
{ 枚举值表 };


举个例子:


enum Week { Sun,Mou,Tue,Wed,Thu,Fri,Sat};


要注意,枚举元素本身由系统定义了一个表示序号的数值,从0 开始顺序定义为0,1,2…。如果我们输出,输出的是其序号。例如我们写如下代码:


#include<iostream>
using namespace std;

enum Week { Sun,Mou,Tue,Wed,Thu,Fri,Sat};

int main(){

Week w = Tue;

cout<<w;

return 0;
}


输出结果就是2:


信息学集训 | 13 枚举算法理论与实战_c++


如果我们想改变其序号,让其从1开始,可以用如下代码:


#include<iostream>
using namespace std;

enum Week { Sun = 1,Mou,Tue,Wed,Thu,Fri,Sat};

int main(){

Week w = Tue;

cout<<w;

return 0;
}


如果序列不要求从小到大有序,可以自己根据需求输入所有的序号。


3、枚举算法的优缺点


优点:算法简单,在局部地方使用枚举法,效果十分的好


缺点:运算量过大,当问题的规模变大的时候,循环的阶数越大,执行速度越慢。

2 枚举条件

枚举算法是有使用条件的,主要有如下两条:


可预先确定候选答案的数量;
候选答案的范围在求解之前必须有一个确定的集合。


3 枚举分类

枚举主要有三种类型,分别是:


1、循环枚举


循环枚举是最常用的,一般是通过循环的方式,从头到尾所有的全部考虑,例如我们输出班里所有同学的名字,我们可以把同学名字存在数组中,通过索引循环枚举所有学生姓名。


2、子集枚举


有些时候通过循环枚举,会出现重复的情况,例如我们最开始说的分组的问题,子集枚举是说,我们把枚举的所有情况分类,分成不同的类别,对于每种类别进行枚举,得到的枚举是总的枚举的子集。


3、排列枚举


排列枚举要和排列组合结合,通过排列组合的方式进行枚举,这要涉及到专业的排列组合知识,在此我们先不展开讲解。


4 枚举算法简单总结

枚举算法简单粗暴,他暴力的枚举所有可能,尽可能地尝试所有的方法。虽然枚举算法非常暴力,而且速度可能很慢,但确实我们最应该优先考虑的!因为枚举法变成实现最简单,并且得到的结果总是正确的。


枚举也不是无脑地考虑所有情况,要有针对性的减少无需考虑的情况来优化算法的复杂度,比如我们下面的例题的第一题。


3 枚举算法经典例题

接下来我们通过几道题目来看下枚举算法吧!

1 找素数

输入一个数n,输出小于n的所有素数。其中,0<n<1000000。


分析1:如果这个数是素数,那么这个数只有1和其本身两个因数。大于这个数的一定不是其因数,所以我们通过循环枚举所有的情况,从因数2开始,判断到小于该数为止。


分析2:前面的方法一定能够覆盖到所有的情况,但是效率比较低,我们能不能减少考虑的次数呢?我们知道,如果这个数是偶数且不为2,那么这个数就不是素数,所以我们只需要判断奇数即可,这样我们就能减少一半运算量。


分析3:还可以再化简吗?当然可以,如果a*b=c,且a<b,那么如果我们知道,如果k*k=c,那如果不存在a≤k,使得a是c的因数,那么大于k的数中一定不存在c的因数,所以我们内层循环执行到k即可。


根据上面的内容,我们已经极大地化简了算法,具体代码如下:


#include<iostream>
using namespace std;

int main(){
int n, flag, k = 0;
cin>>n;
if(n>2) {
cout<<2<<" ";
k++; //统计个数
}
for(int i = 3;i<=n;i+=2){ //只考虑奇数
flag = 1; //flag 如果变为0,说明不是素数
for(int j = 3;j*j<=i;j+=2){
if(i%j==0) {
flag = 0;
continue;
}
}
if(flag){
cout<<i<<" ";
k++;
if(k%10==0) cout<<endl;
}
}
cout<<endl<<k<<endl;

return 0;
}


执行结果如下:


信息学集训 | 13 枚举算法理论与实战_c++_02


2 百钱买百鸡

我国古代数学家张丘建在《算经》一书中曾提出过著名的“百钱买百鸡”问题,该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?


分析1:这道题目,结果不唯一,我们可以列方程解方程,但是解方程的过程比较难通过编程实现,但是我们可以通过枚举所有可能的情况,并做判断,满足百钱买百鸡就输出。鸡翁1值钱5,所以百钱最多买20只鸡翁。鸡母1值钱3,所以百钱最多买33只鸡母,鸡雏3值钱1,所以百钱最多买300只鸡母,但一共只有100只鸡,所以最多买鸡雏100只


代码如下:


信息学集训 | 13 枚举算法理论与实战_c++_03


分析2:我们还可以自己计算枚举所有的情况,并存下来,然后直接输出。


3 求方阵和矩阵

有一个由n*m个同学组成的n行m列的方阵,问这个方阵中包含多少个不同的正方形子方阵和行列不相等的长方形矩阵?


分析:首先我们考虑n行m列能构成的所有矩阵的个数,能构成1行的,有n中情况,能构成2行的,有n-1中情况,……,能构成n行的,有1种情况,所以一共有 (n + 1) * n / 2种情况。能构成1列的,有m种情况,能构成2列的,有m-1中情况,……,能构成m列的,有1种情况,所以一共有 (m + 1) * m / 2种情况。能构成矩阵的情况,就是行的情况×列的情况,即:


(((n + 1) * n) / 2) * (((m + 1) * m) / 2)


接下来我们再考虑正方形方阵,这是因为,正方形方阵行确定了,列也就确定了,更容易计算。对于i行i列的方阵,一共有(n-i+1) * (m-i+1)种情况。所以我们可以写代码如下:


#include<iostream>
using namespace std;
int min(int m, int n){
if(m>n) return n;
return m;
}
int main()
{
int n, m;
int z = 0, c = 0; //正方形、长方形
int sum; //所有情况
cin>>n>>m;
sum = (((n + 1) * n) / 2) * (((m + 1) * m) / 2); //枚举所有的情况
for(int i = 1; i <= min(m, n); i++)
{
z += (n-i+1) * (m-i+1); //枚举i行i列方阵的情况
}
c = sum - z; //矩阵个数是剩下的
cout<<z<<" "<<c<<endl;
return 0;
}


4 作业

本节课的作业,就是复习上面的所有知识,并完成下面的题目!

1 [NOIP2002 普及组] 选数

已知 n 个整数 x_1,x_2,…,x_n,以及1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。求和为素数一共有多少种情况。


例如当n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和如下:


3+7+12=22


3+7+19=29


7+12+19=38


3+12+19=34


上面的四个式子,只有一个为素数。


【输入说明】
键盘输入,格式为:
n,k(1≤n≤20,k<n)
x_1,x_2,…,x_n (1 \le x_i \le 5000000)
【输出说明】
屏幕输出,格式为:1个整数(满足条件的种数)。


【输入示例】
4 3
3 7 12 19
【输出示例】
1




AI与区块链技术

信息学集训 | 13 枚举算法理论与实战_#include_04

长按二维码关注

举报

相关推荐

0 条评论