这天正感无趣,树杈(一哥们儿)发来一个妖题,Google了一下,发现自己孤陋了。随手回了个话,建议他写个程序算算看。几天后见面时,那厮果然写程序算了,据说程序跑了一个下午没有把结果搞出来。听说另外还有一玩VB的兄弟算到程序崩溃也没看到答案。遂兴趣大起,和树杈一下探讨了一下算法,下面是一个效率尚可的解决办法,更高效算法尚在思考中(只是树杈在思考,我已经放弃动脑了,好累啊)。
2#coding: utf8
3'''
4Created on 2009-6-1
5@author: sutra
6
7求满足下列条件的数:
81、它是一个质数;
92、它的各位数字必须是递减的;
103、把它的数字逆转过来,得到各位递增的数字,仍然是个质数;
114、它是满足以上三个条件的数字中最大的一个。
12'''
13
14'''
15删除数位求解法
16'''
17import string
18import math
19
20# 判断一个数是否是素数
21def isprime(prime):
22 i=2
23 limit=int(math.sqrt(prime))
24 for i in range(2,limit+1):
25 if prime % i == 0:
26 return False
27 i=i+1
28 return True
29
30# 从数 a 中删除一位。
31def delete(a, arr):
32 s = str(a)
33 l = len(s)
34
35 for j in range(0, l):
36 b = (a / (10 ** (j + 1)) * (10 ** j)) + (a - a / (10 ** j) * (10 ** j))
37 arr.append(b)
38
39if __name__ == '__main__':
40 # 素数末位不能是0,并且又要递减,所以这里没有0
41 a = 987654321
42 fromarr = [a]
43 toarr = [a]
44 result = []
45
46 l = len(str(a))
47
48 for i in range(1, l):
49 for a in fromarr:
50 delete(a, toarr)
51 result.extend(toarr)
52 fromarr = list(set(toarr))
53
54 result = list(set(result))
55 result.sort()
56 #print result
57
58 prime = []
59 for b in result:
60 if isprime(b) and isprime(int(str(b)[::-1])):
61 prime.append(b)
62
63 prime.sort()
64 print prime[len(prime) - 1]
65
思路比较简单:
1、因为是一个从高位到低位递减的数字,所以最大的一个符合条件的数字是9876543210。
2、以零结尾的数不可能是质数, 所以最大就变成了987654321,一共9位。
3、由于在一个顺序序列中任意删除一个或多个单元,该序列仍然有序,所以我们采用删位的方法来循环。(其实这里应该写个递归,树杈这人太懒了,懒的都快和我看齐了)
4、先看9位的数是否符合要求,如果不符合就从低位到高位穷举删掉1位的状况,看看有没有符合的,如果还没有就在删掉1位的数字的基础上再删掉1位……(明显就是递归嘛)
5、第一个遇到的符合条件的数字就是最大的符合条件的数,答案就是9875321,这个不包含任何政治意义的数字。
这里仅仅解释一下36行那个表达式,这个可读性极低的表达式绝对是偷懒的结果。
其实就像注释所说,希望从一个数字中删掉其中的某1位得到另一个数,我们觉得数学运算应该要比字符串运算要更快,所以写了这个表达式。
其原理很简单,假设要抽调十位上的数字,就把百位以上的数字用整除除出来然后乘以10再加上各位的数字就成了。
今天听说有一个可以提高质数检查效率的算法,持续关注中。