穷举法定义及示例

定义

穷举法是算法设计中经常使用的一种方法,基本思想是问题的要求将问题的所有可能的输入一一进行验证,看是否满足问题的条件,从而找到可能的解。问题解有三种情况:有多个解,单个解或无解。穷举法又名枚举法,暴力破解法等。
使用数学进行表示如下:
Y = F ( X ) ∈ R , w h e r e   X ∈ D . \quad \quad Y=\mathrm{F}(X) \in \mathbb{R} \mathrm{, where} \:X \in \mathbb{D}. Y=F(X)R,whereXD.

此式中:

  • X X X 为问题的输入,其取舍范围定义域为 D \mathbb{D} D;
  • Y Y Y为问题的解,即所要达到的目标;
  • F F F 为问题的解决算法,即 F ​ : ​ X → Y F\!: \!X \rightarrow Y F:XY;
  • R \R R 为解空间,当 R = ∅ \R = \empty R= 时,问题无解 。

使用条件

使用穷举法对所有可能的输入进行测试,因此需要花很多的时间。要让其在可以接受的时间范围内解决问题,需要考虑以下三个条件:

  1. 定义域范围
    定义域 D \mathbb{D} D必需是有限的,或者可以看作有限。有限的范围不能太大。举例来说,15X15的棋盘的五子棋的所有输入可能为 225! 种,约为 1.26 × 1 0 + 433 1.26\times10^{+433} 1.26×10+433
  2. 优化水平
    优化是指将定义域中一些明显不可能的输入在穷举前删除,如五子棋中,第一步是不可能走四边的,这样第一步剩下的格子 (225 - 58) = 167,从而解空间下降了 58/225 = 25.78%。如果再考虑外围两圈,又可以再多减少54个格子,即只要考试113个格子,这样总空间变成了 113 × 254 113\times254 113×254! ,这样解空间基本下降了一半。
  3. 运算能力
    即计算机的运算能力,现在计算机性能越来越强大,而且还可以多台进行联合工作进行并行计算,如在 2019.3.14,谷歌使用 25 虚拟机器用了121天,计算了31.4万亿位的PI。

示例1:鸡兔同笼问题

问题:一个笼子有35个头,94只脚,问鸡和兔各有多少?
分析:设鸡x只,免y只,其中 x + y = 35, 2x+4y=94。
根据题目可以得到x和y的定义域为 x ∈ [ 0 , 35 ] x\in[0,35] x[0,35], y ∈ [ 0 , 35 ] y\in[0,35] y[0,35]
优化:由于 23< 94/4 < 24,所以 y 的值域可取得 y ∈ [ 0 , 24 ] y\in[0,24] y[0,24]
根据以上分析,使用java编码如下:

public static void main(String[] args) {
	for(int x = 0; x <= 35; x++) {
		for(int y = 0; y <= 24; y++) {
			if(x+y==35 && 2*x+4*y==94)
				System.out.printf("x=%d, y=%d.\n", x, y);
		}
	}
}

结果为:

x=23, y=12.

由于使用双层循环,循环次数为36*25=900次。实际上可以将y用35-x表示,这样循环次数减少为36次,效率得到大大提高。

public static void main(String[] args) {
	for (int x = 0; x <= 35; x++) {
		if (2 * x + 4 * (35 - x) == 94)
			System.out.printf("x=%d, y=%d.\n", x, (35 - x));
	}
}

示例2:水仙花数

水仙花数(Narcissistic number)是每个位上的数字的 3次幂之和等于它本身的三位数。例如,153 就是一个水仙花数,因为它满足 13 + 53+ 33 = 153。水仙花数也被称为超完全数字不变数(pluperfect digital invariant, PPDI)、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数(Armstrong number) [2]。

解决思路:鉴于三位数只有900个(100-999),所以只需要遍历一次,判断每个数是否满足条件即可。为了简化操作,解题时可以使用三层循环,自外向内每层分别表示百位、十位和个位数。另外,由于三位数首位不为0,所以范围是1 ~ 9,而其他的位是0 ~ 9。

以下是用 Java 实现的代码。

// i,j,k 分别表示百位、十位和个位数。
for(int i = 1; i < 10; i++)
    for(int j = 0; j < 10; j++)
        for(int k = 0; k < 10; k++)
            if(i * i * i + j * j * j + k * k * k == 100 * i + 10 * j + k)
                System.out.printf("%d is a narcissistic number.\n", 100 * i + 10 * j + k);

输出为:

153 is a narcissistic number.
370 is a narcissistic number.
371 is a narcissistic number.
407 is a narcissistic number.

[1] 谷歌创新PI世界记录,https://www.theverge.com/2019/3/14/18265358/pi-calculation-record-31-trillion-google
[2] 水仙花数,百度百科,https://baike.baidu.com/item/水仙花数/2746160?fr=aladdin

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值