最大公约数和最小公倍数
最大公约数gcd(a,b)
遍历法:取两个数的最小值作为遍历的起点,减一逐个数的尝试,直到能够找到最大公约数,其遍历次数为min{a,b}
欧几里德算法(辗转相除法Euclidean algorithm):
第一步:用较大的数m除以较小的数n得到一个商q0和一个余数r0;
第二步:若r0=0,则n为m,n的最大公因数;若r0≠0,则用除数n除以余数r0得到一个商q1和一个余数r1;
第三步:若r1=0,则r1为m,n的最大公因数;若r1≠0,则用除数r0除以余数r1得到一个商q2和一个余数r2;
……
依次计算直至rn=0,此时所得到的rn-1即为所求的最大公因数。
原理:a,b,m,n都为正整数,c为大于等于零整数,并且a>b,假设n为a,b的最大公约数,则
a = m*b+c => n*a’ = m*n*b’+c => c = n*(a’–m*b’) => b和c的最大公约数为n
该算法可以利用递归方法实现,递归层数为(4.785lgN + 1.6723),其中N=max{a,b}
最小公倍数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)中未知数x,y的 方法
设 a>b
1、显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2、ab≠0时
设 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 的方法:x,y 的值基于 x1,y1.
上面的思想是以递归定义的,因为 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-x2是b’的整数倍。设它为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,其中当c是g=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,删除2p,3p,4p,…,当处理完所有数之后,还没有被删除的就是素数。
改进:对于p可以限定为素数,只需要在第二重循环前加一个判断是否该数已被标记(没有标记表示素数),假如N有大于根号N 的因子,那么它的另一个因子必小于根号N,那么计算机运算时查到这个因子时就可判断它不是素数,因此只需到平方根。并且第二层循环的开始可以从i的平方开始,减少筛选的重复。