数论算法初步理解(1)



最大公约数和最小公倍数

  1. 最大公约数gcd(a,b)

    遍历法:取两个数的最小值作为遍历的起点,减一逐个数的尝试,直到能够找到最大公约数,其遍历次数为min{a,b}

    欧几里德算法(辗转相除法Euclidean algorithm):

    第一步:用较大的数m除以较小的数n得到一个商q0和一个余数r0

    第二步:若r00,则nmn的最大公因数;若r00,则用除数n除以余数r0得到一个商q1和一个余数r1

    第三步:若r10,则r1mn的最大公因数;若r10,则用除数r0除以余数r1得到一个商q2和一个余数r2

    ……

    依次计算直至rn0,此时所得到的rn1即为所求的最大公因数。

    原理:a,b,m,n都为正整数,c为大于等于零整数,并且a>b,假设na,b的最大公约数,则

    a = m*b+c  =>  n*a’ = m*n*b’+c  =>  c = n*(a’–m*b’)  =>  bc的最大公约数为n

    该算法可以利用递归方法实现,递归层数为(4.785lgN + 1.6723)其中N=max{a,b}

  2. 最小公倍数lcm(a,b)

    由于lcm(a,b)*gcd(a,b) = a*b,因此lcm(a,b) =a*b/gcd(a,b)

在代码中,为了防止a*b超过变量范围,建议lcm(a,b) = a/gcd(a,b)*b,先除后乘

具体代码见:https://code.csdn.net/snippets/451429


求解一条直线上的整数点(扩展欧几里得算法)

首先求解ax+by=gcd(a,b)中未知数xy的 方法

a>b

1、显然当 b=0gcdab=a。此时 x=1y=0

2ab0

ax+by=gcd(a,b);

bx1+(a mod b)y1=gcd(b,a mod b);

根据欧几里德原理有gcd(a,b)=gcd(b, a mod b);

:ax+by=bx1+(a mod b)y1;

:ax+by=bx1+(a-[a/b]*b)y1=ay1+bx1-[a/b]*by1;

也就是ax+by=ay1+b(x1-[a/b]*y1);

根据恒等定理得:x=y1; y=x1-[a/b]*y1;

这样我们就得到了求解 x,y 的方法:xy 的值基于 x1y1.

上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以通过递归可以结束。

根据上述方法得到ax+by=gcd(a,b)一组解(x1,y1),任取另外一组解(x2,y2),则ax1+by1=ax2+by2(都等于gcd(a,b)),变形得a(x1-x2)=b(y2-y1)。假设gcd(a,b)=g,方程左右两边同时除以g,得到a’(x1-x2)=b’(y2-y1),a’=a/g,b’=b/g。此时,a’b’互质,因此x1-x2b’的整数倍。设它为kb’,而x1-x2=kb’,y2-y1=ka’。所以x2=x1-kb’,y2=y1+ka’,a’=a/g,b’=b/g, gcd(a,b)=g,其中k取任意整数。

对于ax+by=c,其中当cg=gcd(a,b)的整数倍时,其解为(x0c/g,y0c/g),其中(x0,y0)ax+by=g的一组解;若c不是g的整数倍,则无整数解。

具体代码见:https://code.csdn.net/snippets/451433


Eratosthenes筛法

筛法的思想:根据某种方法标记不符合要求的数,则没有标记的数为所求数

例子:求n以内的所有素数

若对n个数逐个进行判断需要进行n次判断操作,筛法则是将不符合的数直接标记,不用对每个数都进行操作。在素数筛法中,对于不超过n的每个非负整数p,删除2p3p4p,当处理完所有数之后,还没有被删除的就是素数。

改进:对于p可以限定为素数,只需要在第二重循环前加一个判断是否该数已被标记(没有标记表示素数),假如N有大于根号N 的因子,那么它的另一个因子必小于根号N,那么计算机运算时查到这个因子时就可判断它不是素数,因此只需到平方根。并且第二层循环的开始可以从i的平方开始,减少筛选的重复。

具体代码见:https://code.csdn.net/snippets/451434

点赞