java 穷举法求水仙花数_常用算法-穷举法

穷举法又称为枚举法,它是在计算机算法设计中用得最多的一种编程思想。它的实现方式是:在已知答案范围的情况下,依次地枚举该范围内所有的取值,并对每个取值进行考查,确定是否满足条件。经过循环遍历之后,筛选出符合要求的结果来。这种方法充分利用了计算机运算速度快的特点,思路简单直接,能够解决大部分的问题。

什么样的问题适合使用穷举法来解决呢?归纳起来,遇到了如下的三种情况,将优先考虑使用穷举法:

1. 答案的范围已知:

虽然事先并不知道确切的结果,但能预计到结果会落在哪个取值范围内。譬如说:

①求1-100之间所有的素数: 无论结果如何,都在1-100的范围之内。

②求2000-2015年间有几个月的13号是周日?这15年间共有180个月,月份的个数最多不会超过180

③验证1000以内的哥德巴赫猜想:即找出1000之内所有的合数,看是否能够分解为两个质数之和

。。。。。。

如果仔细观察,将会发现许多题目的结果范围都是已知的,都可以使用穷举法来实现。

2. 答案的结果是离散的,不是连续的。如果要求出1-2之间所有的小数,就无法用穷举法来实现,因为其结果是无限连续的。

3. 对时间上的要求不严格。蓝桥杯比赛中的许多题目对于算法的设计是有时间要求的,有时会非常苛刻。如果用穷举法则耗时过长,不可取。例如求出21位的水仙花数,使用穷举法可能会花费30分钟的时间。而蓝桥杯试题通常要求时间限制在1秒钟之内完成,少数会延长至3分钟。在这种情况下,必须使用新的算法来解决问题。

下面举个经典的例子:

100块砖100人来搬,男人一人搬4块,女人一人搬3块,小孩3人抬一块,问男,女,小孩各几人?

若设男,女,小孩人数分别为X, Y, Z,则只能够列出两个等式: X+Y+Z=100  4*X+3*Y+Z/3=100 。三个未知数两个等式,无法求解。这就只能够使用穷举法来实现,具体做法如下:

先确定每种类型人员的数量的取值范围,由题意可知,男人X的取值范围是0~100/4=25 女人Y的取值范围是0~100/3=33 小孩的取值范围是0~99(必须不大于100且为3的倍数)。使用穷举法遍历所有可能的取值结果,逐一判断筛选出正确的结果。编程如下:

for(int x=0; x<=25; x++)

for(int y=0; y<=33; y++)

for(int z=0; z<=99; z+=3)

if((x+y+z==100)&&(4*x+3*y+z/3==100))

{输出找到的结果}

如果仔细分析一下,就会发现由于x+y+z==100,那么只需要考虑x和y的遍历取值;z值可以通过100-x - y来实现。当然,z值是3的倍数,上述代码可修改如下:

for(int x=0; x<=25; x++)

for(int y=0; y<=33; y++)

{

int z = 100 - x - y;

if((z%3==0)&&(4*x+3*y+z/3==100))

{输出找到的结果}

}

从这道题的解决过程中,我们可以发现使用穷举法的一般过程:

确定需要哪几个变量,此题需要3个变量x,y, z  如果是其它的题目,所需变量的个数与类型有可能不尽相同,这个要由具体情况而定。

确定每个变量的取值范围,如上例之中X的范围是0~25, y的取值范围是0~33, z的取值范围是0~33

设置多层的嵌套循环,通常为for循环,最内层之中设置条件判断,满足输出条件时,输出相关的提示信息。

再来一道可以使用穷举法解决的问题:

有一群海盗(不多于20人),在船上比拼酒量。过程如下:打开一瓶酒,所有在场的人平分喝下,有几个人倒下了。再打开一瓶酒平分,又有倒下的,再次重复...... 直到开了第4瓶酒,坐着的已经所剩无几,海盗船长也在其中。当第4瓶酒平分喝下后,大家都倒下了。 等船长醒来,发现海盗船搁浅了。他在航海日志中写到:“......昨天,我正好喝了一瓶.......奉劝大家,开船不喝酒,喝酒别开船......”

请你根据这些信息,推断开始有多少人,每一轮喝下来还剩多少人。 如果有多个可能的答案,请列出所有答案,每个答案占一行。格式是:人数,人数,...

例如,有一种可能是:20,5,4,2,0

蓝桥杯中的许多题目都会提供一个答案的示例,通过分析这个示例可以加深对当前这道题的理解。以本题为例,通过研究示例答案可以看出如下的特点:

(1)答案只可能有4个数,分别代表每轮参与的人数,最后的0是固定的。

(2)每轮的人数是不断减少的,下一轮只能够比上一轮人数更少。

(3)每轮人数被1除之后,累加和是1(刚好一瓶酒)

即 1/20+1/5+1/4+1/2=1

根据上述的分析,可以确定如下的变量s1, s2, s3, s4分别代表每轮的人数。

这四个变量的取值范围分别是 1≤s1≤20   1≤s2≤s1   1≤s3≤s2       1≤s4≤s3  据此来设置4层的嵌套循环,并加上最内层的条件判断如下:

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

if(1/s1+1/s2+1/s3+1/s4==1){输出结果}

理论上来看是正确的,但实际运行时,由于/运算符在左右两边均为整数时,表示整除而不是除法,所以上述的条件判断需要改写为更复杂的形式:

(s1*s2*s3+s1*s3*s4+s1*s3*s4+s2*s3*s4)/(s1*s2*s3*s4)==1

根据笔者指导蓝桥杯的经验,至少有三分之一的问题都可以通过穷举的方法来实现,因此,把穷举法练习使用好,意义非常重大。

作业:

(1) 换分币: 将5元的人民币兑换成1元,5角和1角的硬币,共有多少种不同的兑换方法?

(2) 找完数: 求1~100内完数的个数。 如果一个数等于它的因子之和,则称该数为完数(或“完全数”)。例如,6的因子为1,2, 3 而6=1+2+3 , 因此6是完数

(3)找自守数:自守数是指一个数的平方的尾数等于该数自身的自然数。例如:5*5=25; 25*25=625; 76*76=5776; 9376*9376=87909376, 求100000以内的自守数。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值