枚举
1. 概念
枚举,顾名思义就是遍历每个可能答案,从所有的候选答案中去搜索正确的解,暴力的枚举所有可能。这个算法的优缺点也非常明显:
优点:通过循环就能够轻易实现
,并且得到的结果总是正确的
缺点:非常暴力,而且速度可能很慢
学会这个算法非常简单,只需要会写for循环就可以了……
但是
,通过这个缺点我们就可以知道,如果老老实实的把范围内的所有数都枚举一遍,也就是使用多重for循环是非常慢的,可能会导致TLE。所以枚举算法的核心就在于优化。一般来说,有两个大概的方向
①减少枚举变量
:如果枚举的变量满足一个关系式,那么循环可以少写一层
②缩小枚举范围
:对于不可能有正确答案的范围可以直接舍去
2. 例题
2.1 百鸡问题
2.1.1 题目
一只公鸡5元钱,一只母鸡3元钱,而1元可买3只小鸡。现有n元钱,想买n只鸡,问可买公鸡、母鸡、小鸡各几只?输出方案数。(n<=5000000)
(注意题目数据量,考虑时间复杂度)
样例输入:
100
样例输出:
4
时间限制:
1000
空间限制:
65536
2.1.2 分析
这题可以列出一个方程,设公鸡买i只,母鸡买j只,则小鸡买了(n-i-j)只,所以:
5i+3j+(n-i-j)/3=n,可以得到i与j的数量关系,循环也只用一层了。还有循环的结束条件也要优化哦
2.1.3 代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,ans=0;
cin>>n;
//7i+4j=n
//j=(n-7i)/4
for(int i=0;i<=n/7;i++){
if((n-7*i)%4==0&&n>=7*i){
ans++;
}
}
cout<<ans;
return 0;
}
注:两层循环就会TLE,更别说3层了
2.2 玩玩拉格郎日四平方和定理
2.2.1 题目
题目描述:
拉格朗日四平方和定理:
每一个非负整数都可以表示成四个非负整数的平方和。
例如 5 = 0^ 2 + 0^ 2 + 1^ 2 + 2^2
给定一个正整数n,请你将n拆成 a^ 2+b^ 2+c^ 2+d^2,问 a+b+c+d最小是多少。
输入格式:
一个正整数表示 n。
输出格式:
一个正整数表示答案。
样例输入1:
4
样例输出1:
2
约定:
1<=n<=90000
2.2.2 分析
这道题的方法也很明显,每个for循环枚举一个底数,注意0也是可以的。不过这里最多只能减到三层循环,就没办法优化了。每个for循环的循环次数照样是要减少的。枚举的过程中还要做比大小的操作。
2.2.3 代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,minn=99999;
cin>>n;
for(int i=0;i<=sqrt(n);i++){
for(int j=0;j<=sqrt(n-i*i);j++){
for(int k=0;k<=sqrt(n-i*i-j*j);k++){
int l=sqrt(n-i*i-j*j-k*k);
if(i*i+k*k+j*j+l*l==n&&i+j+k+l<minn){
minn=i+k+j+l;
}
}
}
}
cout<<minn;
return 0;
}
2.3 平方十位数
2.3.1 题目
题目描述:
请找出最大的满足以下条件的十位数:
这个十位数由0~ 9组成,且0~9各出现一次。
这个十位数是一个完全平方数。
输入格式:
无
输出格式:
一个十位数表示答案。
样例输入1:
无
样例输出1:
无
约定:
由于本题的特殊性,本题只有一组测试数据。 为了训练自己的枚举水平,请不要直接提交直接输出答案的程序。
提示:
注意本题时间限制。
2.3.2 分析
看到约定,想偷懒骗分的是不是伤心了?
因为要求最大,我们循环就从最大开始,一旦找到了就return 0。因为这里要求的数是完全平方数,所以可以定义一个int的变量,从999999999的平方根开始到100000000的平方根。这个循环变量的平方如果就是这个数,那说明这个数是完全平方数,否则不是。接着需要考虑的是每个数字是否只出现了一次。可以定义标记的数组vis,记录每个数字出现了几次。如果sum是10,就说明符合条件,输出即可。
2.3.3 代码
#include<bits/stdc++.h>
using namespace std;
int main(){
for(long long n=99381;n>=31990;n--){
long long num=n*n;
int vis[10]={},sum=0;
while(num){
vis[num%10]++;
sum+=vis[num%10];
num/=10;
}
if(sum==10){
cout<<n*n;
return 0;
}
}
return 0;
}
由此可见,枚举的代码一般比较短,只需要for套for就可以了
制作不易,点个赞吧😘