7.1 简单枚举

在枚举复杂对象之前,先尝试着枚举一些相对简单的内容,如整数、子串等。尽管暴力枚举不用太动脑筋,但对问题进行一定的分析往往会让算法更加简洁、高效。

提示7-1:即使采用暴力法求解问题,对问题进行一定的分析往往会让算法更简洁、高效。

例题7-1 除法(Division, UVa 725)

输入正整数n,按从小到大的顺序输出所有形如abcde/fghij = n的表达式,其中aj恰好为数字0~9的一个排列(可以有前导0),2≤n≤79。

样例输入:

62

样例输出:

79546 / 01283 = 62

94736 / 01528 = 62

【分析】

枚举0~9的所有排列?没这个必要。只需要枚举fghij就可以算出abcde,然后判断是否所有数字都不相同即可。不仅程序简单,而且枚举量也从10!=3628800降低至不到1万,而且当abcde和fghij加起来超过10位时可以终止枚举。由此可见,即使采用暴力枚举,也是需要认真分析问题的。

例题7-2 最大乘积(Maximum Product, UVa 11059)

输入n个元素组成的序列S,你需要找出一个乘积最大的连续子序列。如果这个最大的乘积不是正数,应输出0(表示无解)。1≤n≤18,-10≤Si≤10。

样例输入:

3

2 4-3

5

2 5 -1 2 -1

样例输出:

8

20

【分析】

连续子序列有两个要素:起点和终点,因此只需枚举起点和终点即可。由于每个元素的绝对值不超过10且不超过18个元素,最大可能的乘积不会超过1018,可以用long long存储。

例题7-3 分数拆分(Fractions Again?!, UVa 10976)

输入正整数k,找到所有的正整数xy,使得

样例输入:

2

12

样例输出:

2

1/2 = 1/6 + 1/3

1/2 = 1/4 + 1/4

8

1/12 = 1/156 + 1/13

1/12 = 1/84 + 1/14

1/12 = 1/60 + 1/15

1/12 = 1/48 + 1/16

1/12 = 1/36 + 1/18

1/12 = 1/30 + 1/20

1/12 = 1/28 + 1/21

1/12 = 1/24 + 1/24

【分析】

既然要求找出所有的xy,枚举对象自然就是xy了。可问题在于,枚举的范围如何?从1/12=1/156+1/13可以看出,x可以比y大很多。难道要无休止地枚举下去?当然不是。由于xy,有,因此,即y≤2k。这样,只需要在2k范围之内枚举y,然后根据y尝试计算出x即可。