1.引入
扩展欧几里得算法是欧几里得算法(又叫辗转相除法)的扩展。除了计算a、b两个整数的最大公约数,此算法还能找到整数x、y(其中一个很可能是负数)。通常谈到最大公因子时, 我们都会提到一个非常基本的事实: 给予二整数 a 与 b, 必存在有整数 x 与 y 使得ax + by = gcd(a,b)。有两个数a,b,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到ax+by=gcd(a,b)的整数解。
各位应该会记得中学接触的一个问题:给出整数a,b,n,问方程ax+by=n什么时候有整数解,如何求所有的整数解?
其实有解的充分必要条件是gcd(a,b)可以整除n,解释如下:
我们首先令
a=gcd(a,b)*a1,b=gcd(a,b) * b2
则有ax+by=gcd(a,b )*a1x+gcd(a,b) * b1y=gcd(a,b)(a1x+b2y)=n
那如果a1,b1,x,y都为整数的话,那么n/gcd(a,b)也一定是整数,所以n必须是gcd(a,b)的倍数才会有整数解。
例如
4x+6y=8,2x+3y=4有整数解,4x+6y=7就没有整数解
如果确定有解,一种解题方法就是就是先找出一个解(x0,y0),那么通解公式就是如下:
x=x0+bt
y=y0-at ( t是任意整数)
所以这个问题就转换为如何求(x0,y0)了,利用扩展欧几里得算法就可以求出这个特解
2.扩展欧几里得算法
当方程满足ax+by=gcd(a,b)时,可以用扩展欧几里得算法求(x0,y0),程序如下:
void extend_gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
extend_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
有时候为了简化描述,在ax+by=gcd(a,b)两边除以gcd(a,b),得到cx+dy=1,其中c=a/gcd(a,b),d=b/gcd(a,b)。很明显,c和d是互质的,cx+dy=1的通解为
x=x0+dt;
y=y0-ct (t是任意整数)
扩展
1.求任意方程ax+by=n的一个整数解
用扩展欧几里得算法求解ax+by=gcd(a,b)后,利用它可以进一步解任意方程ax+by=n得到一个整数解,其步骤如下:
(1)判断方程ax+by=n是否存在整数解,有解的条件是gcd(a,b)可以整除n
(2)用扩展欧几里得算法求ax+by=gcd(a,b)的一个解(x0,y0)
(3) 在ax0+by0=gcd(a,b)两边同时乘以n/gcd(a,b),得:
ax0n/gcd(a,b)+by0n/gcd(a,b)=n
(4)对照ax+by=n,得到它的一个解(x,y)是:
x=x0n/gcd(a,b)
y=y0n/gcd(a,b)
应用场合
扩展欧几里得算法是一个很有用的工具,在竞赛题目中常用与以下场合:
(1)求解不定方程
(2)求解模的逆元
(3)求解同余方程
虽然用扩展欧几里得算法可以算ax+by=gcd(a,b)的通解,不过一般没有这个需求,而是用于求某些特殊的解,例如求解逆元,逆元是除法求模操作常用的工具