穷举法
穷举法,或称为暴力破解法,其基本思路是:对于要解决的问题,列举出它的所有可能的情况,逐个判断有哪些是符合问题所要求的条件,从而得到问题的解。它也常用于对于密码的破译,即将密码进行逐个推算直到找出真正的密码为止。例如一个已知是四位并且全部由数字组成的密码,其可能共有10000种组合,因此最多尝试10000次就能找到正确的密码。理论上利用这种方法可以破解任何一种密码,问题只在于如何缩短试误时间。因此有些人运用计算机来增加效率,有些人辅以字典来缩小密码组合的范围。
水仙花数
所谓的水仙花数是指:一个三位数,其各个位上的数字的立方和等于该数本身。可见水仙花数介于100到999之间
分析
方法一
设bai ,shi,ge表示这三位数的百位,十位,个位则这三位数ans=bai*100+shi*10+ge
满足以下条件的ans为所求所数
bai=1~9;shi=0~9;ge=0~9
ans==bai3+shi3+ge3
#include<iostream> #include<cmath> using namespace std; int main() { int bai,shi,ge,ans; for (bai=1;bai<10;bai++) { for (shi=0;shi<10;shi++) { for(ge=0;ge<10;ge++) { ans=bai*100+shi*10+ge; if (pow(bai,3)+pow(shi,3)+pow(ge,3)==ans) { cout<<ans<<endl; } } } } }
方法二
设ans是所求的三位数,bai ,shi,ge表示这三位数的百位,十位,个位则这三位数ans=bai*100+shi*10+ge
满足以下条件的ans为所求所数
ans=100~999
将ans拆分成百位数bai=ans/100,十位数shi=ans/10%10,个位数ge=ans%10,找满足下列式子的ans==bai3+shi3+ge3
#include<iostream> #include<cmath> using namespace std; int main() { int bai,shi,ge,ans; for (ans=100;ans<1000;ans++) { bai=ans/100; shi=ans/10%10; ge=ans%10; if (pow(bai,3)+pow(shi,3)+pow(ge,3)==ans) { cout<<ans<<endl; } } }
百元百鸡
今有鸡翁一,值钱伍;鸡母一,值钱三;鸡雏三,值钱一。凡百钱买鸡百只,问鸡翁、母、雏各几何?
方法一
设鸡翁x、母y、雏z只,由题意可以知道满足下列两个等式的x,y,z为本题的解
x+y+z=100且5*x+3*y+z/3=100且x,y,z是非负整数
x,y,z可取的范围0~100
#include<iostream> using namespace std; int main() { int x,y,z; for (x=0;x<=100;x++) { for (y=0;y<=100;y++) { for (z=0;z<=100;z++) { if (x+y+z==100&&5*x+3*y+z/3==100&&z%3==0) { cout<<x<<" "<<y<<" "<<z<<endl; } } } } }
方法二
设鸡翁x、母y、雏z只,由题意可以知道满足下列两个等式的x,y,z为本题的解
x+y+z=100且5*x+3*y+z/3=100且x,y,z是非负整数
x可取的范围0~20
y可取的范围0~33
z可取的范围0~100
#include<iostream> using namespace std; int main() { int x,y,z; for (x=0;x<=20;x++) { for (y=0;y<=33;y++) { for (z=0;z<=100;z++) { if (x+y+z==100&&5*x+3*y+z/3==100&&z%3==0) { cout<<x<<" "<<y<<" "<<z<<endl; } } } } }
方法三
设鸡翁x、母y、雏z只,由题意可以知道满足下列两个等式的x,y,z为本题的解
x+y+z=100且5*x+3*y+z/3=100且x,y,z是非负整数
x可取的范围0~20
y可取的范围0~33
z=100-x-y;
#include<iostream> using namespace std; int main() { int x,y,z; for (x=0;x<=20;x++) { for (y=0;y<=33;y++) { z=100-x-y; if (5*x+3*y+z/3==100&&z%3==0) { cout<<x<<" "<<y<<" "<<z<<endl; } } } }
九宫图
九宫图,就是把1~9九个数字填到3×3,使其每一横坚斜之和都相等
4 9 2
3 5 7
8 1 6
分析
九宫图每格用九个变量a,b,c,d,e,f,g,h,i如下图
a b c
d e f
g h i
每一变量的取值范围为1~9
a+b+c=d+e+f=g+h+i=a+e+i=c+e+g=a+d+g=b+e+h=c+f+i
且每个数学恰好出现一次
砝码称重
现有1g、2g、3g、5g、10g、20g的砝码各若干枚,问用这些砝码可以称出多少种不同的重量。(设砝码的总重量不超过1000克,且砝码只能放在天平的一端)
分析
设1g,2g,3g,5g,10g,20g的砝码分别有a,b,c,d,e,f个。
取1g的砝码k1个 有0~a个
取2g的砝码k2个有0~b个
取3g的砝码k3个有0~c个
取5g的砝码k4个有0~d个
取10g的砝码k5个有0~e个
取20g的砝码k6个有0~f个
可称重量为k1+2*k2+3*k3+5*k4+10*k5+20*k6
分析
由于总重量为1000克,可以设置标识数数,当可以称的重量设为true
最后统计true的数量
//P2347 砝码称重 #include<iostream> using namespace std; int a1,a2,a3,a4,a5,a6; const int tg[6]={1,2,3,5,10,20}; int ans[1001]; int main() { cin>>a1>>a2>>a3>>a4>>a5>>a6; for (int i1=0;i1<=a1;i1++) { for (int i2=0;i2<=a2;i2++) { for (int i3=0;i3<=a3;i3++) { for (int i4=0;i4<=a4;i4++) { for (int i5=0;i5<=a5;i5++) { for (int i6=0;i6<=a6;i6++) { ans[i1*tg[0]+i2*tg[1]+i3*tg[2]+i4*tg[3]+i5*tg[4]+i6*tg[5]]=1; } } } } } } int ans0=0; for (int i=1;i<=1000;i++) { ans0+=ans[i]; } cout<<"Total="<<ans0<<endl; }
找钱
用10元和50元两种纸币组成240元,共有几种方法。
分析
设10元和50元两种纸币各x和y张,问题变化求方程10*x+50*y=240为负整数解的个数。
#include<bits/stdc++.h> using namespace std; int main() { int x,y,ans=0; for (x=0;x<=240/10;x++) { for (y=0;y<=240/50;y++) { if (x*10+y*50==240) ans; } } cout<<ans<<endl; return 0; }
枚举算法是我们在日常中使用到的最多的一个算法,它的核心思想就是:枚举所有的可能。
枚举法的本质就是从所有候选答案中去搜索正确的解,使用该算法需要满足两个条件:
(1)可预先确定候选答案的数量;
(2)候选答案的范围在求解之前必须有一个确定的集合。
程序结构 循环+选择语句
优点:算法简单,在局部地方使用枚举法,效果十分的好
缺点:运算量过大,当问题的规模变大的时候,循环的阶数越大,执行速度越慢
优化:减少枚举元素与范围
注意:不能遗漏,不要重复。