几个常用的数论算法

1、用辗转相除法求最大公约数和最小公倍数

    求两个数a,b的最大公约数,可以用什么方法?尽管依次试除也能得出相应的结果,但是时间效率太低。而且还有一个简单、高效、相当优美的算法——辗转相除法。也许这是最广为人知的数论算法了。

    这个算法的关键在于以下恒等式:gcd(a,b)=gec(b,a mod b)。它和边界条件gcd(a,0)=a 一起构成了以下的程序:

int gcd(int a, int b){return b == 0 ? a: gcd(b, a%b)};


    这个算法成为欧几里得算法。既然是递归,我们免不了就要问一句:会导致栈溢出吗?答案是:不会。可以证明,gcd函数的递归层数不会超过4.785lgN + 1.6723 ,其中N=max{a,b}。值得一提的是,让gcd递归层数最多的是gcd(Fn,Fn-1),其中Fn就是鼎鼎大名的斐波那契数。

 

    另外,利用gcd,还可以求出两个整数a和b的最小公倍数lcm(a,b),只要用这两个数的乘积除以最大公约数即可。即 gcd(a,b)*lcm(a,b)=a*b 。

int lcm(int a, int b){ return a/gcd(a,b) * b};

    注意公式的写法:如果把lcm写成 a*b/gcd(a,b),可能会得到错误的答案——a*b可能会溢出!使用上述写法,只要保证最终结果在int范围之内,这个函数就不会出错。

 

2、筛选素数表

                         

 

 

3、求某个区域内的点:

例:果园里的树排列成矩阵,他们的x和y坐标均是1-99的整数。输入三角形的三点坐标,一次统计每一个三角形内部(包括边界)共有多少课树。如图所示:

           几个常用的数论算法_第1张图片

样例输入:

1.5 1.5  1.5 6.8  6.8 1.5

10.7 6.9  8.5 1.5  14.5 1.5

样例输出:

15

17

最容易想到的方法是逐一判断。对于每个点(x,y),看看它是否在三角形内。但是这种算法有缺陷:当三角形很大时,时间复杂度为O(mn)。肯定会超时。

下面先来看这个函数:

double area2(double x0, double y0, double x1, double y1, double x2, double y2)
{return fabs(x0*y1+x2*y0+x1*y2-x2*y1-x0*y2-x1*y0)};

很明显能看出来这是什么吧,如果两条三角形的边是AB,AC,那么这个函数就是计算两条边的外积,而结果刚好是三角形面积的两倍!

计算方法如下:

 

注意:由于向量不同的方向会导致计算结果分正负,用fabs统一即可。

有了它,判断就很简单了。假设输入三角形为ABC,待判断的点为O,则O在三角形内部或边界上满足的条件为:ABC的面积\OAB的面积+OAC的面积+OBC的面积。

另外为了避免浮点误差,尽量使用fabs(a-b)是否小于一个事先给定的值(如1e-8),如果可能,尽量避免浮点运算。

 

4、抽屉原理

把不少于n+1个的物体放到n个抽屉里,则至少有一个抽屉里的东西不少于两件。

看起来像是废话,但是运用到实际做题中能发挥很强大的功能,如下:

 

例:从自然数中取出任意n个正整数,组成序列a1,a2,...an。证明:存在一段连续的序列和,让和为自然数n的倍数。

我们可以先构造一个序列si=a1+a2+...ai,然后分别对于si取模,如果其中有一个sk%n==0,那么a1+a2+...+ak就一定是n的倍数(该种情况得证)

如果任何一个sk%n != 0 ,那么 si%n 的范围必定在[1,(n-1)]之间。所以原序列就产生了n个余数。

余数有n个,范围有n-1个,所以必定有两个余数会重复,所以sk1与sk2的差是n的倍数。

因为sk1-sk2是一段连续的序列,所以原命题得证。

 

5、杨辉三角与二项式定理

 

二项式计算:

 

         1

       1  1

      1  2  1

     1 3  3  1

    1 4  6  4 1

   1 5 10  10 5 1

  1 6 15 20 15 6 1

杨辉三角里一个很重要的特点点是:每个数字等于上一行的左右两个数字之和。

可用此性质写出整个杨辉三角。即第n+1行的第i个数等于第n行的第i-1个数和第i个数之和,这也是组合数的性质之一。即

 

 

很明显,二项式定理的系数与杨辉三角一致,因此,很容易短时间内求出(a+b)^n中所有项的系数。

注意:写组合公式函数时,避免多项数据的连乘导致的数据溢出。可以用边乘边除的方法。这样,只要所求的最终结果在范围之内,就不会出错。

 

6、斐波那契数列

先考虑一个简单的问题:楼梯有n个台阶,上楼可以一步上1阶,也可以一步上2阶,一共有多少种上楼的方法?

 

可以先这样考虑:假设f(n)为n个台阶的走法总数,把n个台阶的走法分成两类:

1):第一步走1阶,剩下还有n-1阶要走,有f(n-1)种方法。

2):第一步走2阶,剩下还有n-2阶要走,有f(n-2)种方法。

这样,就得到了递推式:f(n)=f(n-1)+f(n-2)。不要忘了边界情况f(1)=1,f(2)=2。

常用的:

    奇数项求和:

   

    偶数项求和:

   

 

将杨辉三角左对齐,成如图所示排列,将同一斜行的数加起来,即得一数列1、1、2、3、5、8、……

f⑴=C(0,0)=1。
f⑵=C(1,0)=1。
f⑶=C(2,0)+C(1,1)=1+1=2。
f⑷=C(3,0)+C(2,1)=1+2=3。
f⑸=C(4,0)+C(3,1)+C(2,2)=1+3+1=5。
f⑹=C(5,0)+C(4,1)+C(3,2)=1+4+3=8。
F⑺=C(6,0)+C(5,1)+C(4,2)+C(3,3)=1+5+6+1=13。
……
F(n)=C(n-1,0)+C(n-2,1)+…+C(n-1-m,m) (m<=n-1-m)

很神奇吧!斐波那契数列和杨辉三角居然是相通的!

你可能感兴趣的:(递归,数论)