欧几里德算法与拓展欧几里德算法详解((Extended) Euclidean Algorithm)

欧几里德算法(Euclidean algorithm)又叫做辗转相除法,用于求最大公约数。这个算法已经十分常见了。扩展欧几里德算法(Extended Euclidean algorithm)是欧几里德算法的扩展(废话……),这个算法在解不定方程的时候十分常见。

搬运自:https://skywt.cn/posts/euclidean-algorithm/
原文公式按照KaTeX语法,与本文不同(当然我经过了修改~),如果本文中公式显示有异常可以到原文查看。

温馨提示:
本文中有大量 KaTeX 公式,请确保浏览器支持,否则卡到超乎你想象。
Windows 可以在控制面板-程序-卸载程序-卸载\更新 Windows 组件中卸载IE浏览器。
本文中 (a,b) 或者 gcd(a,b) 表示 a、b 的最大公约数; a|b 表示 a 整除 b。

欧几里德算法/辗转相除法

在数学中,辗转相除法,又称欧几里得算法(英语:Euclidean algorithm),是求最大公约数的算法。辗转相除法首次出现于欧几里得的《几何原本》(第VII卷,命题i和ii)中,而在中国则可以追溯至东汉出现的《九章算术》。、
——维基百科

代码

在我们日常的题目里辗转相除法已经十分常见了,最大公约数(Greatest Common Divisor)缩写为GCD,所以函数名就是gcd(当然扩欧的函数名就是exgcd)。其主要代码段是这样的:

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

以上代码其实可以优化成以下这样(其实优化的是代码的复杂度,时间空间还是一样):

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

原理和证明

辗转相除法的原理是什么呢?显然gcd(a,b)的作用是求出a、b的最大公约数(在数学语言里直接用(a,b)表示a、b的最大公约数)。如果b为0就返回a的值不难理解,这说明已经找到了最大公约数a。关键在于:

( a , b ) = ( b , a mod b )

关于这个等式证明如下:

a = k b + r r = a k b = a mod b . ( a , b , k , r N + , r < b )

假设 d 是 a、b 的一个公约数,则  d a , d b

d a k b d a mod b

( a , b ) ( b , a mod b )

通俗点说,d是a、b两个数的公约数,又是b、a mod b的公约数,所以a、b的公约数集与b、a mod b的公约数集相同,它们的最大公约数必然也相同。(用 KaTeX 公式真是太爽了)

扩展欧几里德算法

扩展欧几里德算法(Extended Euclidean algorithm)就像是欧几里德算法的逆运算。

用途

主要有以下几种用途:

  1. 求解不定方程;
  2. 求解模线性方程(线性同余方程);
  3. 求解模的逆元。

求解不定方程的方法

个人觉得求解不定方程这个用途比较常见。可以方便地用来解这样的不定方程(传说中的裴蜀等式):

a x + b y = c

其实我们要解这个补不定方程,就要先解出ax+by=gcd(a,b)。基于这两个事实:

  1. 给予二个整数a、b,必存在整数x、y,使得 ax+by=gcd(a,b)
  2. 对于方程 ax+by=c,当且仅当 gcd(a,b)|c 时这个方程有解。

容易证明,如果我们求出方程 ax+by=gcd(a,b) 的一组特殊解x0、y0,则最后方程解为:

{ x = x 0 + b ( a , b ) y = y 0 a ( a , b )

那么如何“求出方程 ax+by=gcd(a,b) 的一组特殊解”?这时候拓展欧几里德算法就派上用场了。

代码

二话不说,先上代码:

int exgcd(int a,int b,int &x,int &y){ //x、y变量用来传递求得的特殊解
    if(b==0){ //判断递归边界,b=0说明到底了
        x=1;y=0;
        return a;
    }
    int r=exgcd(b,a%b,x,y),t=x; //先递归把之前的都做完
    x=y;y=t-a/b*y;
    return r;
}

原理与证明

先举个例子吧,求不定方程 1234x+4321y=1 的整数解。
首先求(1234,4321),过程如下:

( 1234 , 4321 ) = ( 1234 , 619 ) = ( 615 , 619 ) = ( 615 , 4 ) = ( 3 , 4 ) = ( 3 , 1 ) = ( 0 , 1 ) = 1

我们得到了(1234,4321)=1。接下来用扩展欧几里德算法可以倒着推回去:

1 = 1 0 _

= 1 ( 3 3 1 ) = 3 2 1 _

= ( 4 2 3 ) 3 = 4 3 3 _

= 4 ( 615 153 4 ) = 154 4 _ 615

= 154 ( 619 615 ) 615 = 154 619 155 615 _

= 154 619 155 ( 1234 619 ) = 309 619 _ 155 1234

= 309 ( 4321 3 1234 ) 155 1234 = 309 4321 _ 1082 1234 _

所以这一组特解就是:x=-1082, y=309。按照这样的思路,前面的程序就不难理解了。先递归求x和y,再把x“复原”。

来自:https://skywt.cn/posts/euclidean-algorithm/


参考

查数学知识的时候才意识到百度百科是多么地垃圾……

辗转相除法 - 维基百科,自由的百科全书
扩展欧几里得算法 - 维基百科,自由的百科全书
扩展欧几里德算法详解 - CSDN博客
欧几里德与扩展欧几里德算法 - jumping_frog - 博客园
欧几里德算法的扩展-求解不定方程 - void-man - 博客园
数论初步:辗转相除法和扩展欧几里得 - CSDN博客

猜你喜欢

转载自blog.csdn.net/qq_15033645/article/details/80762253
今日推荐