扩展欧几里得算法

来源:互联网 发布:数据集成平台的作用 编辑:程序博客网 时间:2024/05/02 01:34
扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。
欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:
gcd函数就是用来求(a,b)的最大公约数的。
gcd函数的基本性质:
gcd(a,b)=gcd(b,a)=gcd(-a,b)=gcd(|a|,|b|)
公式表述
gcd(a,b)=gcd(b,a mod b)
证明:a可以表示成a = kb + r,则r = a mod b
假设d是a,b的一个公约数,则有
d|a, d|b,而r = a - kb,因此d|r
因此d是(b,a mod b)的公约数
假设d 是(b,a mod b)的公约数,则
d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公约数
因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。
C++语言实现
int gcd(int a,int b){
    return b?gcd(b,a%b):a;

}

扩展的欧几里得算法:

对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在无数组整
数对 x,y ,使得 gcd(a,b)=ax+by。
c++语言实现
int e_gcd(int a,int b,int &x,int &y){
    if (b==0){
        x=1,y=0;
        return a;
    }
    int ans=e_gcd(b,a%b,y,x);
    int temp=x;
    x=y;
    y=temp-a/b*y;
    return ans;

}

POJ1061:

思路:
   根据题意,两个青蛙跳到同一个点上才算是遇到了,所以有 (x+m*t) - (y+n*t) = p * ll;  (t是跳的次数,ll是a青蛙跳的圈数跟b青蛙的圈数之差。整个就是路程差等于纬度线周长的整数倍),
转化一下: (n-m) * t + ll * p = x – y;
令 a = n-m,  b = ll,  c = gcd(a, b),  d = x-y;
有 a * t + b * p = d;   (1)
要求的是t的最小整数解。
用扩展的欧几里德求出其中一组解t0 ,p0, 并令c = gcd(a, b);
有 a * t0 + b * p0 = c;  (2)
因为c = gcd(a, b), 所以 a * t / c是整数,b * t / c 也是整数,所以 d / c 也需要是整数,否则无解。
 (2)式两边都乘(d / c) 得 a * t0 *(d / c) + b * p0 * (d / c) = d;
 所以t0 * (d / c)是最小的解,但有可能是负数。
因为a * ( t0 *(d / c) + b*n) + b * (p0 * (d / c) – a*n) = d; (n是自然数)
所以解为 (t0 * (d / c) % b + b) % b;
还有一个问题,如何用扩展的欧几里德求出t0跟p0呢?
    对于不完全为0的非负整数a, b.  gcd(a, b)表示a, b 的最大公约数。那么存在整数x, y使得 gcd(a, b) = a * x + b * y;
不妨设a > b
① ,当b = 0 时,gcd(a, b) = a , 此时 x = 1, y = 0;
② ,当 a * b <> 0 时,
 设 a * x + b * y = gcd(a, b);   (1)
    b * x0 + (a % b) * y0 = gcd( b, a % b);   (2)
由朴素的欧几里德公式; gcd(a, b) = gcd (b, a % b);
得(1),(2)  a * x + b * y = b * x0 + (a % b) * y0
                     = b * x0 + (a – a / b * b) * y0               
                     = a * y0 + ( x0 – a / b * y0 ) * b
          所以 x = y0, y = x0 – a / b * y0;
由此可以得出扩展欧几里德的递归程序。
 
0 0