有一类问题可以采用一种盲目的搜索方法,在搜索结果的过程中,把各种可能的情况都考虑到,并对所得的结果逐一进行判断,过滤掉那些不符合要求的,保留那些符合要求的,这种方法叫枚举算法。
并不是所有的问题都可以使用枚举算法来求解,只有当问题的所有可能解的个数不太多时,并在可以接受的时间内得到问题的所有解,才有可能使用枚举算法 。
例题
1.林大 OJ 8 二倍的问题
第一个方法,简单排序
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a[20],ans,j;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
j=0;
scanf("%d",&a[j]);
while(a[j]!=0)
{
j++;
scanf("%d",&a[j]);
}
sort(a,a+j);
ans=0;
for(int x=0;x<j;x++)
for(int i=x+1;i<j;i++)
{
if(a[i]==a[x]*2)
ans++;
}
printf("%d\n",ans);
}
return 0;
}
第二个方法,桶排序,但是我这个桶排序码得很麻烦,还用了二维数组,大家就参考参考
对于桶排序的理解
比如这个数值为X,就把它存放在X桶中,我们需要设置桶的数量(即排序的范围),把数据放到与之匹配的桶里,改变记录桶有多少个数据的变量(一定要在装数据之前初始化),输出时要遍历所有桶,选数据不为0的数据输出,按编号输出即可。
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int n,a[100][100],j,i,b[100][100],p[1000],maxx[1000],m; //二维数组,桶排序
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
j=0;
maxx[i]=-1111; //随便写一个负值就可
scanf("%d",&a[i][j]);//输入第i行第j个数值
while(a[i][j]!=0)//不等于0的话,下面接着循环输入
{
b[i][a[i][j]]=1; //表示第i行数值为a[i][j](即第i行第j个数值 )的个数为1
if(a[i][j]>maxx[i])
{
maxx[i]=a[i][j];
//求出最大值,即最大的桶
}
j++; //第i行元素+1
scanf("%d",&a[i][j]);
}
}
for(i=1;i<=n;i++)
{
p[i]=0;
for(j=0;j<=maxx[i];j++)
{
if(b[i][a[i][j]*2]==1) //第i行中2倍的a[i[][j]仍然存在
p[i]++;
}
printf("%d\n",p[i]);
}
return 0;
}
2.林大OJ 573 大乐透
理解
定义六个循环变量,i1,i2,i3,i4,i5,i6。a[i1]-a[i6]为从k个数中取出的六个数,它们之间的关系为i1<i2<i3<i4<i5<i6按顺序输出。因此a[i1]只能为前k-5个数中的一个, a[i2]只能为前k-4个数中的一个……最后依次输出a[i1]-a[i6]。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[100],i,k;
scanf("%d",&k);
while(k!=0)
{
for(i=1;i<=k;i++)
scanf("%d",&a[i]);
for(int i1=1;i1<=k-5;i1++)
for(int i2=i1+1;i2<=k-4;i2++)
for(int i3=i2+1;i3<=k-3;i3++)
for(int i4=i3+1;i4<=k-2;i4++)
for(int i5=i4+1;i5<=k-1;i5++)
for(int i6=i5+1;i6<=k;i6++)
printf("%d %d %d %d %d %d\n",a[i1],a[i2],a[i3],a[i4],a[i5],a[i6]);
scanf("%d",&k);
}
return 0;
}
3.林大 OJ 572 密码箱
理解
他已经试到第n个了,接下来从n+1试起,分为 一位数 两位数 三位数 情况讨论,一位数前面补上00,两位数前面补上0
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
nt main()
{
int n;
while(scanf("%d",&n)!=-1)
{
for(int i=n+1;i<1000;i++)//简单的依次网上循环
{
if(i<10)
printf("00%d\n",i);
if(10<=i&&i<100)
printf("0%d\n",i);
if(i>=100)
printf("%d\n",i);
}
}
return 0;
}
4.林大 OJ 193 字符串统计
理解
暴力查找每一个字符是否为数字即可
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k,j;
char a[101];
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++) //循环输入每行
{
scanf("%s",a);
j=0;
k=0;
while(a[j]!='\0')
{
if('0'<=a[j]&&a[j]<='9')
k++; //统计数字数量
j++;
}
printf("%d\n",k);
}
}
return 0;
}
5.林大OJ 574 丑数
理解
第一个丑数为“1”,后面的每一个丑数都是前面的丑数乘 2,3,5,7
每一个丑数乘上2,3,5,7,成为另一个丑数
x2,x3,x5,x7:xm位置前的丑数已乘过m,
x2:第一次为1,若x2所在位置的丑数已被乘2,则x2需向后移,x3,x5,x7依此类推
每次找丑数就是找到2a[x2],3a[x3],5a[p5],7a[x7]的最小值,
判断n位置的丑数属于哪种类型,说明xm已乘过m,xm位置+1
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int x2,x3,x5,x7;
int a[5900];
int main()
{
int i,n;
a[1]=1;
x2=x3=x5=x7=1;
for(i=2;i<=5842;i++)
{
a[i]=min(min(a[x2]*2,a[x3]*3),min(a[x5]*5,a[x7]*7));//对获取的丑数进行排序
if(a[i]%2==0) x2++;
if(a[i]%3==0) x3++;
if(a[i]%5==0) x5++;
if(a[i]%7==0) x7++;
}
scanf("%d",&n);
while(n!=0)
{
printf("%d\n",a[n]);
scanf("%d",&n);
}
return 0;
}
6.;林大OJ 575矩形
理解
在纸上画两个矩形,观察坐标的关系
先锁定每个矩形,循环暴力枚举其他矩形(包括它自己)能否覆盖自己 若能 +1
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct ju
{
int x1,x2,y1,y2;
};
int main()
{
ju p[1000];
int n,k,sum,i,j;
while(scanf("%d",&n)!=EOF)
{
sum=0;
for(i=1;i<=n;i++)
scanf("%d %d %d %d",&p[i].x1,&p[i].x2,&p[i].y1,&p[i].y2);
for(i=1;i<=n;i++)
{
k=0;
for(j=1;j<=n;j++)
{
if(p[i].x1>=p[j].x1&&p[i].x2<=p[j].x2&&p[i].y1>=p[j].y1&&p[i].y2<=p[j].y2)
k++;
}
if(k==n)
sum++;
}
printf("%d\n",sum);
}
return 0;
}
7.林大OJ 1639 抽奖
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,a[100],i,j,num;
scanf("%d",&n);
j=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
} //循环输入所有号码
scanf("%d",&num);
for(i=1;i<=n;i++)
{
if(num==a[i]) //查找是否有中奖号码
{
printf("%d",i);
}
if(num!=a[i])
j++;
}
if(j==n) //找了n个都没有相同号码,即没有中奖
printf("0");
return 0;
}
8.林大 OJ 比身高
理解
循环查找他前面和他后面每个人的身高是否比他高,计算他前面和他后面比他高的人数
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,i,a[1001],j,p,q,t,x;
scanf("%d",&n);
t=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(i=1;i<=n;i++)
{
p=0;q=0;
for(j=i-1;j>0;j--) //从他前面的人向前循环到第一个人
if(a[j]>a[i])
p++; //统计比他高人数
}
for(x=i+1;x<=n;x++) //从他后面的人向后循环到最后一个人
{
if(a[x]>a[i])
q++; 统计比他高人数
}
if(p==q)
t++;
}
printf("%d",t);
return 0;
}
9.林大OJ 1642 楼层编号
理解
**
穷举楼层编号,判断数字是否含高能数字,将所有含高能数字t的楼层计数存储在k中
假设一个数字123456,将它的每一位分离,6最好办,123456%10=6,之后可以先除10,123456/10=12345,再进行模十运算,12345%10=5…
这样子就能把所有的位数找出来,判断是否有t**
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t,m,k,p,s;
scanf("%d %d",&m,&t);
k=0;
for(int i=1;i<=m;i++)
{
s=i;
while(s>0) //该循环为循环判断每一位是否等于高能数字
{
p=s%10; //取余
if(p==t)
{
k++;
break;
}
s=s/10; //取模
}
}
printf("%d",m-k);
return 0;
}
10.林大OJ 1643 比例简化
理解
利用gcd求出最大公约数,要使分子分母互质,最大公约数为1,让分子分母均从1取到L,判断每次情况下分子分母的最大公约数是否为1,即是否互质,循环找出差值最小的分子分母
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
} //求最大公约数
int main()
{
double minn,k1,k2,A,B;
int x,y,i,L,j;
minn=10086;//随便设一个数就可
scanf("%lf %lf %d",&A,&B,&L);
for(i=1;i<=L;i++)
{
for(j=1;j<=L;j++)
{
if(gcd(i,j)==1)
{
k1=1.0*i/j;
k2=1.0*A/B;
if(k2<=k1&&k1-k2<minn)
{
minn=k1-k2;
x=i;
y=j;
}
}
}
}
printf("%d %d",x,y);
return 0;
}
11.林大OJ 1644奶牛碑文
理解
*因为只有 3 个字母,‘O在中间位置,所以可以穷举字符串中的每一个“O”,假设位置 i,然后分别计算其左边“C” 的个数 c[i] 和右边“W” 的个数 w[i],再利用乘法原理进行计数 c[i]w[i],每次把答案累加
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long n,k,p[111111],q[111111],s,f,sum,i;
char a[111111];
int main()
{
scanf("%lld",&n);
scanf("%s",a);
for(i=0;i<n;i++)
{
if(a[i]=='C') //从前往后查找C
f++;
p[i]=f; //记录i位置前的C有f个
}
for(i=n-1;i>=0;i--) //从后往前查找W
{
if(a[i]=='W')
s++;
q[i]=s; //记录i位置后的W有s个
}
for(i=0;i<n;i++)
{
if(a[i]=='O')
sum=sum+p[i]*q[i];
}
printf("%lld",sum);
return 0;
}