水仙花数是指,一个3位数,它的每位数的3次幂之和等于它本身。水仙花数有4个:153, 370, 371, 407。
而自幂数是水仙花数的扩展,它指的是一个n位数,它的每位数的n次幂之和等于它本身。
大一的时候,C语言老师曾让我们编写程序计算5位数以内的自幂数。当时我们的思路是穷举。例如计算5位数的自幂数,穷举10000~99999内的所有数,找出符合条件的数即可。
但是,若数字很大,例如10位及以上的,这样的算法就支撑不住了。
(关键词:可重复组合)!!!
前几天学习Python,发现可以使用Python的itertools库里的combinations_with_replacement可重复组合方法,大大提升计算速度。
例如,我们要找11位数的自幂数,我们只需从0~9这10个数字里取出11个可重复数字(例如(1,1,1,1,1,1,1,1,1,1,1), (2,2,2,2,2,2,2,2,2,2,2), (1,2,3,4,5,6,7,8,9,0,1)等),构造可重复组合,然后依次对每个组合里的数进行验证,即计算每个数的11次幂之和sum,然后再比较len(str(sum))是否等于11,如果是,则计算sum各位11次幂之和是否为sum,如果是则输出sum。这样利用可重复组合,就不需要从10000000000穷举到99999999999了。果然快很多,已经能跑到29位了。
from itertools import combinations_with_replacement as com
from time import perf_counter as per
def nar(n):
powarr = []
for i in range(10):
powarr.append(i ** n)
for c in com(range(10), n):
s = sum(powarr[i] for i in c)
if len(str(s)) == n and sum(powarr[(ord(i) - 48)] for i in str(s)) == s:
yield(s)
def main():
for n in range(1, 40):
start = per()
print(n, "位数的自幂数有", sorted(list(nar(n))),"\n耗时:", per() - start, "s\n")
if __name__ == '__main__':
main()
1 位数的自幂数有 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
耗时: 0.0005798000000000018 s
2 位数的自幂数有 []
耗时: 8.729999999999849e-05 s
3 位数的自幂数有 [153, 370, 371, 407]
耗时: 0.00029869999999999897 s
4 位数的自幂数有 [1634, 8208, 9474]
耗时: 0.0010171999999999994 s
5 位数的自幂数有 [54748, 92727, 93084]
耗时: 0.0029996999999999975 s
6 位数的自幂数有 [548834]
耗时: 0.0080555 s
7 位数的自幂数有 [1741725, 4210818, 9800817, 9926315]
耗时: 0.019855199999999996 s
8 位数的自幂数有 [24678050, 24678051, 88593477]
耗时: 0.0455187 s
9 位数的自幂数有 [146511208, 472335975, 534494836, 912985153]
耗时: 0.09426789999999999 s
10 位数的自幂数有 [4679307774]
耗时: 0.2000364 s
11 位数的自幂数有 [32164049650, 32164049651, 40028394225, 42678290603, 44708635679, 49388550606, 82693916578, 94204591914]
耗时: 0.5384791 s
12 位数的自幂数有 []
耗时: 0.8060039999999999 s
13 位数的自幂数有 []
耗时: 1.3891908999999998 s
14 位数的自幂数有 [28116440335967]
耗时: 2.5009005 s
15 位数的自幂数有 []
耗时: 4.860277999999999 s
16 位数的自幂数有 [4338281769391370, 4338281769391371]
耗时: 9.4189296 s
17 位数的自幂数有 [21897142587612075, 35641594208964132, 35875699062250035]
耗时: 13.097966700000004 s
18 位数的自幂数有 []
耗时: 22.228616199999998 s
19 位数的自幂数有 [1517841543307505039, 3289582984443187032, 4498128791164624869, 4929273885928088826]
耗时: 35.4807801 s
20 位数的自幂数有 [63105425988599693916]
耗时: 53.20027060000001 s
21 位数的自幂数有 [128468643043731391252, 449177399146038697307]
耗时: 87.7056431 s
22 位数的自幂数有 []
耗时: 130.33216760000002 s
23 位数的自幂数有 [21887696841122916288858, 27879694893054074471405, 27907865009977052567814, 28361281321319229463398, 35452590104031691935943]
耗时: 188.28141319999997 s
24 位数的自幂数有 [174088005938065293023722, 188451485447897896036875, 239313664430041569350093]
耗时: 264.5516602 s
25 位数的自幂数有 [1550475334214501539088894, 1553242162893771850669378, 3706907995955475988644380, 3706907995955475988644381, 4422095118095899619457938]
耗时: 471.38872850000007 s
26 位数的自幂数有 []
耗时: 485.95830150000006 s
27 位数的自幂数有 [121204998563613372405438066, 121270696006801314328439376, 128851796696487777842012787, 174650464499531377631639254, 177265453171792792366489765]
耗时: 613.5496306 s
28 位数的自幂数有 []
耗时: 815.2740477000002 s
29 位数的自幂数有 [14607640612971980372614873089, 19008174136254279995012734740, 19008174136254279995012734741, 23866716435523975980390369295]
耗时: 991.4711625 s