穷举算法
举个简单的例子,找素数。1什么都不是,2是素数,3是,4不是,5是……,如此把所有的自然数(当然是不可能的,只能尽量多)都找一遍,就能找出所有的素数。
可以这么说,枚举是最简单,最基础,也是最没效率的算法,但是。枚举拥有很多优点,以致于他能够活到现在而不被淘汰。首先,枚举有超级无敌准确性,只要时间足够,正确的枚举得出的结论是绝对正确的。其次,枚举拥有天下第一全面性,因为它是对所有方案的全面搜索,所以,它能够得出所有的解。例:找偶数。
【题目一】把一元钞票换成一分、二分、五分硬币(每种至少一枚),有哪些种换法?
【答案】461种
提示:
for i:=1 to 93 do
for j:=1 to 47 do
for k:=1 to 19 do
if 100=i+2*j+5*k then n:=n+1;
还有没有效率更高的算法呢?留给大家考虑。
思路:
这些题本身超简单。。。。。
因为要求硬币每种至少一枚,100-(1+2+5)=92,即三种硬币的和只要凑出92就满足题意。
从5分的硬币开始凑,可有效减少循环次数。
92减去5分和2分的硬币的总面额得到的便是1分硬币的个数。
#include<stdio.h>
void main()
{
int sum=0;
for(int i=0;i<=20;i++)
{
for(int j=0;j<=50;j++)
if(92-5*i-2*j>=0)
sum++;
}
printf("%d\n",sum);
}
【题目二】将1,2...9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:2:3的比例,试求出所有满足条件的三个三位数.
分析:这是1998年全国分区联赛普及组试题(简称NOIP1998pj,以下同)。此题数据规模不大,可以进行枚举,如果我们不加思地以每一个数位为枚举对象,一位一位地去枚举:
for a:=1 to 9 do
for b:=1 to 9 do
………
for i:=1 to 9 do
这样下去,枚举次数就有99次,如果我们分别设三个数为x,2x,3x,以x为枚举对象,穷举的范围就减少为93,在细节上再进一步优化,枚举范围就更少了。
思路:
将x作为基准,计算2x、3x的值,再判断3组数的每一位是否都不相同即可。
#include<stdio.h>
void main()
{
int i,a,fal,n;
for(i=123;i<333;i++)
{
fal=0;
int flag[10]={0};
for(int j=1;j<=3;j++){
n=i*j;
while(n)
{
a=n%10;
if((flag[a]==0)&&(a!=0))
{
flag[a]=1;
n=n/10;
}
else
{
fal=1;
break;
}
}//while
if(fal==1)
break;
}
if(fal==0)
printf("%d %d %d\n",i,2*i,3*i);
}
}
运行结果:
192 384 576
219 438 657
273 646 819
327 654 981
【题目三】:穷举法中穷举方案的选择:
陈婷有一个E-MAIL邮箱的密码是一个5位数。但因为有一段比较长的日子没有打开这个邮箱了,陈婷把这个密码给忘了。不过陈婷自己是8月1日出生,而她妈妈的生日则是9月1日,她特别喜欢把同时是8l和9l的倍数用作密码。陈婷还记得这个密码的中间一位(百位数)是l。你能设计一个程序帮她找回这个密码吗?
本问题的数学模型是:
求出一个5位数,它的百位是l,而且它能同时被81和9l整除。
#include<stdio.h>
void main()
{
int n=99999/7371;
int x;
for(int i=1;i<=n;i++){
x=7371*i;
if(x>=10000&&x<100000&&(x/100%10==1))
printf("%d\n",x);
}
}
运行结果:22113