Project-Euler第69题

本文分享了一种使用暴力计算方法解决Project Euler第69题的经验,介绍了如何通过遍历和计算找出最大比值的正整数n及其欧拉函数值。从逐个检查不大于n的数是否与n互质,到利用素数筛选提高效率,再到最终的质因数分解优化,展示了逐步优化算法的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大学的时候挺喜欢解Project Euler上的题目的,尤其是它不在乎答题者使用哪一门编程语言,甚至还有很多参与者是使用pen&paper来解题的。去年开始重新开始做Project Euler上的题目,而第69题则是最近刚刚解决的一题。惭愧的是,因为不晓得欧拉函数的计算公式(甚至都没有想过欧拉函数有没有可以用来计算的公式),所以这一题我是用暴力计算的方法来解决的。尽管花了40分钟左右才找出了问题的答案,但欧拉函数的计算方法本身还是让我觉得挺有意思的,下面我就来讲讲我在计算欧拉函数方面做的一些尝试。

69题本身很容易读懂,就是要找到一个不大于一百万的正整数n,这个n与以它为参的欧拉函数值的比值能够达到最大。欧拉函数的介绍可以看维基百科,简而言之,就是在不大于n的正整数中与n互质的数的个数,具体的例子可以参见69题描述中给出的表格。

网上可以找到别人的解法,基本的思路是:按从小到大的顺序,对于一百万以内的每个素数,都计算出它们的倍数的欧拉函数值的一部分——即对于素数p计算出1-1/p并与这个位置上原来的值相乘。当遍历完一百万以内的所有素数后,也就计算出每一个位置上的欧拉函数值,再遍历一次就可以计算出比值最大的数字了。

但我今天要讲的是笨方法。

笨方法的关键就是乖巧地计算出每一个数字的欧拉函数值。而其中最笨的,当属挑出每一个不大于n的因数,计算它们与n的最大公约数,并根据这个最大公约数是否为1,来决定是否给某一个计数器加一。示例代码如下

(defun phi (n)
  (let ((count 0))
    (dotimes (i n count)
      (when (= (gcd (1+ i) n) 1)
        (incf count)))))

这个phi可以稍微改进一下。例如,如果一个数a与n不是互质的,那么a的倍数(小于n的那一些)也一定不会与n互质。因此,每当遇到这么一个因数a,就知道后续的2a3a等等,都不再需要计算其与n的最大公约数了。改进后的算法代码如下

(defun phi (n)
  "通过将不互质的比特设置为1并计算为0的比特的个数来计算phi函数"
  (let ((bits (make-array n :element-type 'bit :initial-element 0))
        (count 0))
    (dotimes (i n)
      (cond ((= (bit bits i) 1)
             ;; 该比特已经为1,说明已经在比它小的倍数被处理时一并被标记了
             )
            ((= i (1- n))
             ;; 只处理比上界要小的数字
             )
            ((/= (gcd (1+ i) n) 1)
             ;; 除了当前这个不互质的数字之外,还需要将这个数字的倍数也一并处理
             (dotimes (j (floor n (1+ i)))
               (let* ((j (1+ j))
                      (m (* (1+ i) j)))
                 (setf (bit bits (1- m)) 1))))
            (t (incf count))))
    count))

为了节省内存空间,这里用了一个bitmap来标记小于n的每一个数字是否与n互质——1表示不互质,0表示互质。

其实并不需要遍历所有比n小的数字,只要遍历所有n的素因子即可。比如,将8分解为素因子,就是3个2,那么对于小于8的所有2的倍数(4和6)都是与8不互质的。基于这个方法,将所有的素因子的倍数所对应的位置为1,再数一下总共有多少个0比特即可。

对每个n都进行质因数分解效率不高,先生成一个一百万以内的素数表吧

(defun primep (n)
  (cond ((< n 2) nil)
    ((= 2 n) t)
    (t
     (let ((bnd (truncate (sqrt n))))
       (labels ((rec (test)
              (cond ((> test bnd) t)
                ((= 0 (rem n test)) nil)
                (t (rec (1+ test))))))
         (rec 2))))))

(defvar *primes-in-1000000* nil)
(defun generate-primes-in-1000000 ()
  (dotimes (i 1000000)
    (when (primep (1+ i))
      (push (1+ i) *primes-in-1000000*)))
  (setf *primes-in-1000000* (nreverse *primes-in-1000000*)))

然后对于一个给定的n,遍历所有小于它的素数并对相应的倍数所在的比特置一就可以了,示例代码如下

(defun phi3 (n)
  "直接用素数表来做筛法"
  (prog
      ((bits (make-array n :element-type 'bit :initial-element 0)))
     (dolist (num *primes-in-1000000*)
       (cond ((> num n)
              (go :return))
             ((zerop (mod n num))
              (labels ((aux (i)
                         (when (< i n)
                           (setf (bit bits i) 1)
                           (aux (+ i num)))))
                (aux (1- num))))))
     :return
     (return-from phi3
       (count-if (lambda (bit) (zerop bit)) bits))))

PS:写这个phi3的时候发现Common Lisp提供了一个prog宏,这个宏倒是真的挺好用。

改进了两轮,其实这仍然是笨方法。即便是用phi3,用来计算题目的答案也花了40多分钟。

全文完

内容概要:本文档提供了关于“微型车间生产线的设计与生产数据采集试验研究”的毕业设计复现代码,涵盖从论文结构生成、机械结构设计、PLC控制系统设计、生产数据采集与分析系统、有限元分析、进度管理、文献管理和论文排版系统的完整实现。通过Python代码和API调用,详细展示了各个模块的功能实现和相互协作。例如,利用SolidWorks API设计机械结构,通过PLC控制系统模拟生产流程,使用数据分析工具进行生产数据的采集和异常检测,以及利用进度管理系统规划项目时间表。 适合人群:具有机械工程、自动化控制或计算机编程基础的学生或研究人员,尤其是从事智能制造领域相关工作的人员。 使用场景及目标:①帮助学生或研究人员快速搭建和理解微型车间生产线的设计与实现;②提供完整的代码框架,便于修改和扩展以适应不同的应用场景;③作为教学或科研项目的参考资料,用于学习和研究智能制造技术。 阅读建议:此资源不仅包含详细的代码实现,还涉及多个学科领域的知识,如机械设计、电气控制、数据分析等。因此,在学习过程中,建议读者结合实际操作,逐步理解每个模块的功能和原理,并尝试调整参数以观察不同设置下的系统表现。同时,可以参考提供的文献资料,深入研究相关理论和技术背景。
的学生体质健康信息管理网站,按照用户的角色可以分为教师与学生,后台设置管理员角色来对学生的信息进行管理。,设计如下: 1、后台管理系统 后台管理系统主要是为该系统的管理员提供信息管理服务的系统,具体包括的功能模块如下: (1)管理员信息管理 (2)教师信息管理 (3)学生信息管理 (4)健康信息统计(图形化进行健康,亚健康等学生的信息数量统计) 2、教师角色的功能模块设计 教师角色所需要的功能模块主要包括了如下的一些内容: (1)个人资料修改 (2)学生体质健康管理:录入相关数据,包括但不限于身高、体重、肺活量、视力等生理指标以及运动能力、身体成分、骨密度等健康指标,并且设置健康,亚健康状态 (3)学生健康建议:根据体质信息,进行学生健康的建议 (4)健康预警:对健康出问的学生,进行健康预警 (5)饮食和锻炼情况管理,查看 3、学生角色 学生角色可以通过该信息网站看到个人的基本信息,能够看到教师给与学生的健康建议等,功能模块设计如下: (1)个人资料修改 (2)我的健康建议查看 (3)我的健康预警 (4)饮食和锻炼情况管理,记录平时的饮食和锻炼情况 完整前后端源码,部署后可正常运行! 环境说明 开发语言:Java后端 框架:ssm,mybatis JDK版本:JDK1.8+ 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:eclipse/idea Maven包:Maven3.3+ 部署容器:tomcat7.5+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值