数学专题(三)、欧几里得与扩展欧几里得

五一之前再更一发,话说要为今年的邀请赛做准备了,但是我还什么都不会啊QAQ

今天主要更Euclid这个人发明的算法。欧几里得算法(Euclidean Algorithm),又称辗转相除法,是用来求解两个数的最大公约数的一种算法。其主要的思想是,设有正整数a,b,不妨令a>b,且a mod b≠0. gcd( a , b )=gcd( b , a mod b ),证明如下:

由于a mod b≠0,设a=k*b+r,即a mod b=r.设gcd( a , b )=c,则c|a且c|b.

令a=m*c,b=n*c且mn互质,r=a-k*b=m*c-n*c*k=(m-n*k)c,也即c|r. 由于n与m-n*k互质,(证:若n与m-n*k不互质,设gcd(n,m-n*k)=d,且d>1.令n=xd,m-n*k=yd,且xy互质,则y+xk与x互质。gcd(a,b)=gcd(xcd,(y+xk)cd)=cd>c,与假设矛盾)所以gcd( b , r )=c=gcd( a , b ).证毕。代码的话很好写,一行递归就搞定了,在这儿就不放上来了。

然后要说的是扩展欧几里得算法(extended Euclidean algorithm)。exgcd的主要思想为:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。下证:

设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax 1+ by 1= gcd(a,b);
bx 2+ (a mod b)y 2= gcd(b,a mod b);
根据朴素的 欧几里得原理有 gcd(a,b) = gcd(b,a mod b);
则:ax 1+ by 1= bx 2+ (a mod b)y 2;
即:ax 1+ by 1= bx 2+ (a - [a / b] * b)y 2=ay 2+ bx 2- [a / b] * by 2;
说明: a-[a/b]*b即为mod运算。[a/b]代表取小于a/b的最大整数。
也就是ax 1+ by1 == ay 2+ b(x 2- [a / b] *y 2);
根据恒等定理得:x 1=y 2; y 1=x 2- [a / b] *y 2;
这样我们就得到了求解 x 1,y 1 的方法:x 1,y 1 的值基于 x 2,y 2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
#include
using namespace std;

long long exgcd(long long a,long long b,long long& x,long long& y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    long long r=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return r;
}

int main(){
    long long a,b,c,d;
    while(cin>>a>>b>>c>>d){
        cout<

辣么exgcd有什么用呢?至少有以下3个作用:

1、求解不定方程;

2、求解模线性方程(线性同余方程);

3、求解模的逆元。

关于求解不定方程,可以参考这一篇博客http://www.cnblogs.com/void/archive/2011/04/18/2020357.html

关于求解同余方程和乘法逆元,实际上都是把他们转化成ax+ ny= b的方程形式求解。

同余方程 ax≡b (mod n)对于未知数 x 有解,当且仅当 gcd(a,n) | b。且方程有解时,方程有 gcd(a,n) 个解。

设 d= gcd(a,n),假如整数 x 和 y,满足 d= ax+ ny(用扩展欧几里德得出)。如果 d| b,则方程

a* x0+ n* y0= d, 方程两边乘以 b/ d,(因为 d|b,所以能够整除),得到 a* x0* b/ d+ n* y0* b/ d= b。
所以 x= x0* b/ d,y= y0* b/ d 为 ax+ ny= b 的一个解,所以 x= x0* b/ d 为 ax= b (mod n ) 的解。

ax≡b (mod n)的一个解为 x0= x* (b/ d ) mod n,且方程的 d 个解分别为 xi= (x0+ i* (n/ d ))mod n {i= 0... d-1}。

设ans=x*(b/d),s=n/d;

方程ax≡b (mod n)的最小整数解为:(ans%s+s)%s;

相关证明:

证明方程有一解是: x0 = x'(b/d) mod n;
由 a*x0 = a*x'(b/d) (mod n)
     a*x0 = d (b/d) (mod n)   (由于 ax' = d (mod n))
             = b (mod n)

证明方程有d个解: xi = x0 + i*(n/d)  (mod n);
由 a*xi (mod n) = a * (x0 + i*(n/d)) (mod n)
                         = (a*x0+a*i*(n/d)) (mod n)
                         = a * x0 (mod n)             (由于 d | a)
                         = b

证毕。



你可能感兴趣的:(算法)