线性表出与扩展欧几里得算法
欧几里得算法就是求最大公约数的辗转相除法,这次来仔细看一下算法执行过程中发生了什么:
左侧蓝色部分代表每一轮的参数如何得到,将它们改写一下就是右边红色部分。在细说红色部分之前,先来介绍一下“线性表出”的概念
考研数学的线性代数中,向量组部分有这么一条定义:对于向量组{→α1,→α2,…,→αn}和同维度的向量→β,存在一组不全为0的数{k1,k2,…,kn},使得→β=∑ni=1(ki·→αi),则称向量组{→α1,→α2,…,→αn}可以线性表出向量→β,如果向量是1维的,则它们可以看成一个单独的数
然后再来看红色的每一行,15=48−33∗1表示48,33可以线性表出15,3=33−15∗2表示33,15可以线性表出3,而gcd(48,33)就是3.上述过程已经表明了48,33可以线性表出它们的最大公约数3.由此,我们可以从任意的整数方程a∗x+b∗y=gcd(a,b)中找到x,y的解
再用中间每一步的参数来线性表出一下它们的最大公约数,可得下图中绿色部分:
绿色部分正说明了求解a∗x+b∗y=gcd(a,b)相当于求解b∗x0+(a%b)∗y0=gcd(a,b),而a%b在数学上的表示就是a−b∗⌊a/b⌋,关于a,b合并同类项可得a∗y0+b∗(x0−⌊a/b⌋∗y0)=gcd(a,b)。在辗转相除的过程中不断地作x=y0,y=x0−⌊a/b⌋∗y0这样的变换,一直到b=0为止,此时对应的x,y分别为1,0
C++ 代码
/**
* @brief 扩展欧几里得算法
* @param a,b 待求gcd的一对数
* @param x,y a*x+b*y=gcd(a,b)的解(引用传递)
* @return gcd(a,b)
* @warning x,y可能是负数,因此不能使用size_t类型
*/
int exGcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int d = exGcd(b, a % b, x, y), ox = x, oy = y;
//自底向上变换
x = oy;
y = ox - (a / b) * oy;
return d;
}