枚举算法:也称穷举算法,它是编程中常用的一种算法。在解决某些问题的时候,可能无法按照一定规律从众多的候选答案中找出正确的答案。此时,可以从众多的候选解中逐一取出候选答案,并验证候选答案是否为正确的答案。这种方法就是枚举算法。
缺点:运算量比较大,接替效率不高。如果枚举的范围太大,在时间上就难以承受。
优点:思路简单,程序编写和调试方便。
下面是书上的一个例子,判断n是否能被3,5,7整除。
问题:输入一个正整数n,判断n是否能被3,5,7整除,并输出以下信息:
(1)能同时被3,5,7整除。
(2)能同时被其中两个数(要指出哪两个数)整除。
(3)能被其中一个数整除。
(4)不能被任何一个整除。
我之所以喜欢这个例子,是因为里面的解法太妙了,一开始看的时候还看不懂,里面用了二进制的知识,还有整数位运算的知识,思路很有逻辑,结构很清晰!
很多一开始学语言的朋友见到此题也不会觉得很难,因为只要学了if……else语句,就可以解答此题。
比如:
if(n%3==0 && n%5==0 && n%7==0)
cout<<"该整数能同时被3,5,7整除"<<endl;
else…………
这样依次判断当然能够解决这个题目,但是,下面的解法会更妙!
如果n能被整除用1表示,不能用0表示。用三位二进制数表示n是否能被3,5,7整除的结果,从高位到低位来表示。如:001 表示能被7整除,010能被5整除,100能被3整除,当然011表示能被5,7同时整除。
于是,定义三个变量a,b,c,作为三个位数,然后,利用位运算的知识,m= ((a<<2)+(b<<1)+c),这样m作为十进制来说,取值范围便是0~7。也就是8种情况,然后,再想想,题目中输出的结果共有几种?!没错!就是8种,那么,刚好一一对应,例如:a=1(能被3整除),b=0(不能被5整除),c=1(能被7整除),m=((a<<2)+(b<<1)+c).
即,m = 100+000+001(二进制),即m = 5,表示,整除能同时被3,7整除!好了,问题就这样解决了,是不是很妙呢?
下面是程序:
- #include<iostream>
- using namespace std;
- int main()
- {
- int a,b,c,n,m;
- cout<<"请输入一个整数: "<<endl;
- cin>>n;
- a=n%3==0;
- b=n%5==0;
- c=n%7==0;
- m = ((a<<2)+(b<<1)+c);
- switch(m)
- {
- case 0:
- cout<<"不能被3,5,7整除!"<<endl;
- break;
- case 1:
- cout<<"只能被7整除!"<<endl; //(000)+(000)+(001)
- break;
- case 2:
- cout<<"只能被5整除!"<<endl;
- break;
- case 3:
- cout<<"能被5,7整除!"<<endl; //(000)+(010)+(001)
- break;
- case 4:
- cout<<"只能被3整除!"<<endl;
- break;
- case 5:
- cout<<"能被3,7整除!"<<endl;
- break;
- case 6:
- cout<<"能被3,5整除!"<<endl;
- break;
- case 7:
- cout<<"能同时被3,5,7整除!"<<endl;
- break;
- }
- return 0;
- }
下面是运行结果:
这再一次证明了:计算机程序=数据结构+算法,而且算法是程序的灵魂,对任何工程问 题,当用软件来实现时,必须选取满足当前的资源限制,用户需求限制,开发时间限制等种 种限制条件下的最优算法。而绝不能一拿到手,就立刻用最容易想到的算法编出一个程序了 事——这不是一个专业的研发人员的行为。
那么,那种最容易想到的算法就完全没有用吗?不,这种算法正好可以用来验证新算法 的正确性,在调试阶段,这非常有用。在很多大公司,例如微软,都采用了这种方法:在调 试阶段,对一些重要的需要好的算法来实现的程序,而这种好的算法又比较复杂时,同时用 容易想到的算法来验证这段程序,如果两种算法得出的结果不一致(而最容易想到的算法保 证是正确的),那么说明优化的算法出了问题,需要修改。