鱼C论坛

 找回密码
 立即注册
查看: 2165|回复: 8

[技术交流] 小练习:20170424 考察具有有趣性质的平方数链

[复制链接]
发表于 2017-4-23 20:23:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 冬雪雪冬 于 2017-5-1 15:53 编辑

从现在开始我们要开展一批欧拉计划的习题练习。
其实在我们论坛中已有欧拉计划的板块,可能有些鱼油还没注意到。
什么是欧拉计划:http://bbs.fishc.com/thread-60405-1-1.html
我们欧拉板块现已给出了200余题,这批练习将从欧拉计划中选题。其实用python语言完成有很多的优势,可以更简洁更方便的实现。
如果大家有兴趣也可浏览欧拉的英文网站:https://projecteuler.net/archives
这里已经有了500余题。


                               
登录/注册后可看大图


题目要求:
以python语言完成,如果是python2请注明。
程序以代码文字格式发帖。
注重程序效率和创意。
答题在一周内完成,即5.1 10:00之前,其后将公开大家的答案,并评比成绩。

另程序和答案可以在网上搜到,希望大家独立完成。题目不难,大家看看谁的效率高。

----回帖需写明解题思路,鼓励在程序中加上注释


一些鱼油反映题目有些过难,为此略过一部分偏难的题目。





题目:

通过将一个数各位的平方不断相加,直到遇到已经出现过的数字,可以形成一个数字链。

例如:
44 → 32 → 13 → 10 → 1 → 1
85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89

因此任何到达 1 或 89 的数字链都会陷入无限循环。令人惊奇的是,以任何数字开始,最终都会到达 1 或 89。

以一千万以下的数字 n 开始,有多少个 n 会到达 89?

提示:
无需每个数都算到89或1,例如20算出了89,那么42算到20就可以判断了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-4-24 10:21:21 | 显示全部楼层
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. # python 2.7

  4. dict_res = {}
  5. cnt_89 =0
  6. dict_tmp = {}
  7. def fact(n,n_):
  8.     if dict_res.get(n):
  9.             return dict_res[n]
  10.     if n==1:
  11.             dict_res[n_] =0
  12.             return 0
  13.     if n ==89:
  14.             dict_res[n_] =1
  15.         return 1
  16.     tmp_ = n
  17.     if dict_tmp.get(tmp_):
  18.             n = dict_tmp[tmp_]
  19.             return fact(n,n_)
  20.     tmp =map(int,str(n))
  21.     n=reduce(lambda x,y:x+y**2,tmp[1:],tmp[0]**2)
  22.     dict_tmp[tmp_]=n
  23.     return fact(n,n_)

  24. i =1
  25. while i<10000000:
  26.     tmp = fact(i,i)
  27.     cnt_89 += tmp
  28.     i=i+1
  29. print cnt_89
复制代码

8581146
[Finished in 54.8s]

评分

参与人数 1荣誉 +10 鱼币 +10 收起 理由
冬雪雪冬 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-24 13:01:33 | 显示全部楼层
用了一个列表来对应键值关系,本质上还是穷举计算每一个数,所以用时要20多秒。
  1. import time
  2. start = time.time()

  3. def get_sum(x):
  4.     total = 0
  5.     while x:
  6.         x, temp = divmod(x, 10)
  7.         total += temp * temp
  8.     return total
  9. D = [0] * 600
  10. D[1], D[89] = 1, 89
  11. c = 0
  12. for i in range(1, 10000000):
  13.     lst = []
  14.     i = get_sum(i)
  15.     while not D[i]:
  16.         lst.append(i)
  17.         i = get_sum(i)
  18.     for e in lst:
  19.         D[e] = D[i]
  20.     if D[i] == 89:
  21.         c += 1
  22. print(c)
  23. print('Time used: %.3f sec' % (time.time() - start))
复制代码

8581146
Time used: 20.694 sec

评分

参与人数 1荣誉 +10 鱼币 +10 贡献 +10 收起 理由
冬雪雪冬 + 10 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-25 11:39:39 | 显示全部楼层
  1. # import logging


  2. def cal(interger):
  3.     temp_num = sum(map(lambda x: int(x) ** 2, interger))
  4.     # logging.debug(f'{str(temp_num)}')
  5.     return str(temp_num)


  6. # logging.basicConfig(level=logging.INFO)

  7. finish_useful = {'89'}
  8. finish_useless = {'1'}
  9. finish = finish_useless | finish_useful
  10. for start in range(1, 568):             # 9999999=9**2*7=567
  11.     start = str(start)
  12.     # logging.debug(f'{start}')
  13.     temp = {start}
  14.     while start not in finish:
  15.         start = cal(start)
  16.         temp.add(start)
  17.     if start in finish_useful:
  18.         finish_useful |= temp
  19.         finish |= temp
  20.     else:
  21.         finish_useless |= temp
  22.         finish |= temp

  23. result = len(finish_useful)
  24. for start in range(568, 10000000):
  25.     start = str(start)
  26.     if cal(start) in finish_useful:
  27.         result += 1
  28. print(result)
复制代码

评分

参与人数 1荣誉 +10 鱼币 +10 收起 理由
冬雪雪冬 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-25 16:08:14 | 显示全部楼层
  1. import time
  2. def compute(n):
  3.     s = 0
  4.     while n != 0:
  5.         m = n % 10
  6.         s += m**2
  7.         n = n // 10
  8.     return s

  9. start = time.time()
  10. a = []
  11. for i in range(1, 570):##7个9最多只能到567
  12.     s = i
  13.     while True:
  14.         s = compute(s)
  15.         if s == 89:
  16.             a.append(1)
  17.             break
  18.         if s == 1:
  19.             a.append(0)
  20.             break

  21. mid = time.time() ##检测构建指示数组花费的时间

  22. n = 0
  23. for i in range(1, 10**7):
  24.     if a[compute(i) - 1]:
  25.         n += 1

  26. end = time.time()
  27. t1 = mid - start
  28. t2 = end - mid
  29. t = end - start
  30. print(t1, t2, t)
复制代码

用了接近30s,感觉斜率不高

评分

参与人数 1荣誉 +10 鱼币 +10 收起 理由
冬雪雪冬 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-28 17:29:02 | 显示全部楼层
从1到9999999,最大就是7个数都是9,那每位数平方求和就是7*81就是567。所以我就先把567以内的数都划分到1组和89组,之后大于567的数只需要求出平方之和,找处在那个组就行,不过最终花费的时间还是比较长的,为了节约求平方的时间,直接用了字典把0~9和其平方数对应起来。
  1. one=[]
  2. nine=[]
  3. zd={0:0,1:1,2:4,3:9,4:16,5:25,6:36,7:49,8:64,9:81}
  4. def jc1(i=1):
  5.     a=[int(x) for x in list(str(i))]
  6.     he=sum([zd[x] for x in a])
  7.     if he in one:
  8.         return 1
  9.     elif he in nine:
  10.         return 0
  11.     elif he==1:
  12.         return 1
  13.     elif he==89:
  14.         return 0
  15.     else:
  16.         return jc1(he)
  17.    
  18. oo=0
  19. nn=0
  20. for i in range(1,568):
  21.     if jc1(i):
  22.         one.append (i)
  23.         oo+=1
  24.     else :
  25.         nine.append(i)
  26.         nn+=1
  27. for i in range(568,10000000):
  28.     if jc1(i):
  29.         oo+=1
  30.     else:
  31.         nn+=1
  32. print('有%d个结果是1,有%d个结果是89。'%(oo,nn))
复制代码

  1. RESTART: C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\test.py
  2. 有1418853个结果是1,有8581146个结果是89。
  3. >>>
复制代码

评分

参与人数 1荣誉 +10 鱼币 +10 收起 理由
冬雪雪冬 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-4-28 22:23:51 | 显示全部楼层
  1. ##10^7里 各个位数平方和最大的是486(999,999 81*6)
  2. ##分两部分讨论,1-486和486-10^7之间的数



  3. #设立两个列表,分别存放1-486最后结果1和89的数据
  4. set1=set([1])
  5. set89=set([89])

  6. for i in range(1,487):
  7.     num=i
  8.     flag=True
  9.     while flag:
  10.         num=sum(map(lambda x:int(x)**2,list(str(num))))
  11.         if num in set1:
  12.             set1.add(i)
  13.             flag=False
  14.         elif num in set89:
  15.             set89.add(i)
  16.             flag=False

  17. n=len(set89)

  18. #大于486的数,其各个位数的平方和一定在1-486之间,判断是否在set89即可。

  19. for i in range(487,10**7+1):
  20.     num=sum(map(lambda x :int(x)**2,list(str(i))))
  21.     if num in set89:
  22.         n+=1

  23. print(n)
复制代码


新人尝试,运行时间有点长。。。还望见谅

评分

参与人数 1荣誉 +10 鱼币 +10 收起 理由
冬雪雪冬 + 10 + 10

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-1 16:22:03 | 显示全部楼层
  1. n = []
  2. al =[]#最终平方和是89的平方和列表
  3. for i in range(1,10000001):
  4.     iii = i
  5.     al2 = []
  6.     while True:
  7.         a = 0#a表示平方和
  8.         ii = str(i)
  9.         for each in ii:
  10.             a += int(each)**2
  11.         al2.append(a)
  12.         if a == 89 or a in al:
  13.             n.append(iii)
  14.             al.extend(set(al2))
  15.             al = list(set(al))#把重复的平方和去掉,提高一点效率
  16.             break
  17.         elif a == 1:
  18.             break
  19.         else:
  20.             i = a
  21.             continue
复制代码



脑子都要炸了,按我的逻辑来说应该没错,10万个数一秒不到就算完了,但是再加个零变成100万就好像陷入无限循环,算不出。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-7-4 21:11:44 | 显示全部楼层
  1. '''不分段,用时稍久
  2. def sl(n):#递归并记录所有计算过程,字典用于保存一个数对应的最终计算数值
  3.     if n in jh:return jh[n]#返回最终的值
  4.     ls=sl(sum(pf[i] for i in str(n)))#递归开始,计算下一个数
  5.     #ls=sl(sum(map(lambda x:pf[x],list(str(n)))))#用时4.3,循环比lambda快?
  6.     if n<800 :jh[n]=ls#设置n的条件,减少对字典操作
  7.     return ls

  8. import time
  9. tt=time.time()
  10. n=10**7

  11. #jh={i:0 for i in range(600)}
  12. jh={}
  13. jh[1],jh[89]=1,89
  14. pf={str(i):i*i for i in range(10)}#字典比列表快
  15. print(sum(1 for i in range(1,n) if sl(i)==89))#列表推导比循环快
  16. print(time.time()-tt)

  17. '''
  18. #分段式
  19. def sl(n):#递归
  20.     if n in jh:
  21.         return jh[n]#返回最终的值
  22.     return sl(sum(pf[i] for i in str(n)))#递归

  23. def sl2(n):#递归并记录所有计算过程,字典用于保存一个数对应的最终计算数值
  24.     if n in jh:return jh[n]#返回最终的值
  25.     ls=sl(sum(pf[i] for i in str(n)))#递归开始,计算下一个数
  26.     jh[n]=ls #生成集合
  27.     return ls

  28. import time
  29. tt=time.time()
  30. n=10**7
  31. jh={}
  32. jh[1],jh[89]=1,89
  33. pf={str(i):i*i for i in range(10)}#读取字典比列表快?
  34.    
  35. print(sum(1 for i in range(1,811) if sl2(i)==89)+sum(1 for i in range(811,n) if sl(i)==89))#列表推导比循环快
  36. print(time.time()-tt)


复制代码


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-17 07:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表