欧拉项目【ProjectEuler】系列-第一题

简介: 欧拉项目【ProjectEuler】系列-第一题 ----人既无名 既然是第一次,当然要写个基本的介绍咯。 欧拉项目是一系列挑战数学/计算机编程的问题. 需要的不仅仅是数学见解,还要利用计算机编程技巧,需要解决大多数问题,当然,数学帮助你运用优雅而有效的方法,实现漂亮而快速的代码。 欧拉项目的网站是http://projecteuler.net,只要上去注册一个账号就可以开

欧拉项目【ProjectEuler】系列-第一题

----人既无名
既然是第一次,当然要写个基本的介绍咯。
欧拉 项目是一系列挑战数学/计算机编程的问题. 需要的不仅仅是数学见解,还要利用计算机编程技巧,需要解决大多数问题,当然,数学帮助你运用优雅而有效的方法,实现漂亮而快速的代码
欧拉项目的网站是http://projecteuler.net,只要上去注册一个账号就可以开始你的欧拉之旅了,当你把一个问题解决之后就可以参加该问题的讨论,说说你的解决办法,看看其他人的处理思路咯。言归正传,开始欧拉项目的第一题咯。
Problem 1:If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. 
The sum of these multiples is 23.Find the sum of all the multiples of 3 or 5 below 1000.
意思就是:求出1000以下3或者5的倍数的自然数的和。

分析1:

3的倍数可以简单表示为 n%3==0.
5的倍数可以简单表示为 n%5==0.
3或者5的倍数就可以表示为  (n%3)&&(n%5)==0
因此,最简单的办法就是遍历1-999,判断该数是不是3或者5的倍数,是就加上,不是就跳过
int Fuc1()
{//Lazy way
    int sum = 0;
    int i=0;
    for( i = 1; i < 1000; ++i)
        if(0==((i % 3) && (i % 5)))
            sum += i;  
    return sum;
}

分析2:

1000以下3的倍数
序列1:3 6 9 12 15 18 ... 999
5的倍数有
序列2:5 10 15 ... 995 (注意是1000以下,不包括1000)
我们是不是可以把这些数加起来作为最终的和呢?
很显然,两个序列中都有
序列1:15 30 ... 990(3和5的公倍数,也就是15的倍数)。
因此如何把序列1和序列2 加起来和还要减去序列3.

sum=序列1+序列2-序列3;
这个也是我最初的思路。 整个代码也就是
int MyFuc() 
{
	int sum = 0;
	int i;
	//序列1
	for(i=3;i<1000;i+=3)
	{
		sum+=i;	
	}
	//序列2
for(i=5;i<1000;i+=5)
	{
		sum+=i;	
	}
	//序列3,注意是减去
for(i=15;i<1000;i+=15){sum-=i;}
	
	return sum;
 }

分析3:

可能会有人注意到,在我的第二个分析实现是第三步是减去序列3,也就是序列3的数实际上被访问了两遍,有没有更好的办法只将所有的目标数只访问一遍就能求出结果呢?在来分析这些序列的特点
3 5 6 9 10 12 15 18 20 21 24 25 27 30 33 35 36 39 40 ...

除去3的倍数,即序列1,剩下的部分可以发现分为两个序列

5 20 35 ...
10 25 40 ...
因此优化后的代码为
int MyFuc2() 
{
	int sum = 0;
	int i;
	//序列1
	for(i=3;i<1000;i+=3)
	{
		sum+=i;	
	}
	//序列2
for(i=5;i<1000;i+=15)
	{
		sum+=i;	
	}
	//序列3
for(i=10;i<1000;i+=15)
	{
		sum+=i;
	}
	
	return sum;
 }

当然我们完全可以把这段代码用汇编来实现,这是我用VC6下实现的汇编代码:

int Fuc3(){
	int sum;
_asm{
    	xor   edx,edx           ;sum
	mov   eax,3
A:  	cmp eax,1000
	jnl B
      	add   edx,eax
      	add   eax,3
	jmp A
B:    	mov   eax,5
B1:	cmp eax,1000
	jnl C
      	add   edx,eax
      	add   eax,15
	jmp B1
C:    	mov   eax,10
C1:	cmp eax,1000
	jnl D
      	add   edx,eax
      	add   eax,15
	jmp C1
D:	mov sum,edx
    }
	return sum;
}

此时我已经沉浸在胜利的喜悦中,因为我的代码优化已经达到了汇编级别,将上述4个函数分别运行1000000次测试结果显示,从最开始需要6.898秒到现在只要0.618秒,运行的速度得到了10倍左右的提升。具体的运行参数如下表:

函数 运行特点 运行时间(s)
Fuc1() 最原始的方法 6.898
MyFuc() 序列1+序列2-序列3 2.093
MyFuc2() 优化后的序列法 1.569
Fuc3() 汇编优化 0.618
Fuc5() 等差数列求和公式 0.103

最后的分析:

难道真的这样就完了吗?如果现在要求把1000改成1000000会怎样?我们还是虚心看看别人写的东西吧!要想知道速度快不快还得和别人的比较才行。
再回到我最初的想法:
序列1+序列2-序列3
如果现在真的要求把1000改成1000000,我还有从3,6 ,9遍历到999999吗?
3,6,9,...,999999
5,10,15,...,999995
15,30,...,999990
这三个序列都是等差数列啊,高中不就学过等差数列求和的方法吗?
对于等差数列a1,a2,...,an,其中an=a1*dn,他们的和Sn为:
Sn=(a1+an)*n/2;
或者
Sn=a1*(1+dn)*n/2;

等等,通过这个公式是就可以快速求出3个等差序列的和
如,对于序列1:
999/3=333
序列1的和=3+6+9+...+333=3*(1+333)*333/2
同样
999/5=199(取整即可)
序列2的和=5+10+...+995=5*(1+199)*199/2
999/15=66
序列2的和=15+30+...+990=15*(1+66)*66/2
sum=3*(1+333)*333/2+5*(1+199)*199/2+15*(1+66)*66/2;
设计一个求序列和的函数SumSeiresBy(int n)
int SumSeiresBy(int n)
{
	int p=999/n;
	return n*(1+p)*p/2;
}
最终求和可以写成
int Fuc5()
{
	int sum;
   	sum=SumSeiresBy(3)+SumSeriesBy(5)-SumSeresBy(15);
	return sum;
}

运行1000000次的时间为0.103秒(见表1),要不要这么狠,比我的汇编代码还快,我下巴都快掉了,这就是一个高中送分的题啊,被我们想得这么复杂,笔算都可以很快算出来啊。

不过有一点是值得我们思考的,在学习了很多是数学知识后我们没有很好的将它们利用起来,遇到问题就以为用暴力的方式解决,不仅成效不高,还达不到优雅美观,有失个人风范。而欧拉项目的目的是用数学帮助你运用优雅而有效的方法,实现漂亮而快速的代码。数学什么时候都不会过时。



相关文章
|
3月前
|
安全 Shell Linux
openEuler OECA认证课程习题答案
本文整理了OECA认证课程的每章节课后习题答案。
79 2
openEuler OECA认证课程习题答案
|
4月前
|
数据可视化 数据处理 Apache
初窥Apache DolphinScheduler
初窥Apache DolphinScheduler
45 0
|
4月前
|
Kubernetes 算法 调度
基于kube-scheduler-simulator编写自己的调度程序
基于kube-scheduler-simulator编写自己的调度程序
51 0
|
9月前
带你走进ER图
带你走进ER图
71 0
|
9月前
|
数据库
er图-为什么画er图?有哪些规范?
提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型。我认为就是用来描述程序产生的数据之间的关系。
|
索引
LeetCode 207. Course Schedule
现在你总共有 n 门课需要选,记为 0 到 n-1。 在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
59 0
LeetCode 207. Course Schedule
|
存储 NoSQL 关系型数据库
|
算法
【欧拉计划第 1 题】Multiples of 3 or 5
【欧拉计划第 1 题】Multiples of 3 or 5
【欧拉计划第 1 题】Multiples of 3 or 5
|
大数据 算法框架/工具
[Project Euler] 来做欧拉项目练习题吧: 题目013
问题描述: Work out the first ten digits of the sum of the following one-hundred 50-digit numbers. 3710728753390210279879799822083759024651013574025046376...
931 0
|
算法框架/工具
微分方程数值分析基础:Euler法
微分方程数值分析基础:Euler法 Euler法作为数值分析的一种方法,主要解决微分方程在求出精确公式没有必要,求不到或者非常困难情况下有用。
1591 0

热门文章

最新文章