扩展欧几里得
欧几里得算法
众所周知,扩欧是从欧几里得来的。
本部分来自这里
链接内有两种证明
欧几里德算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式 g c d ( a , b ) = g c d ( b , a m o d b ) 。 gcd(a,b) = gcd(b, a \bmod b)。 gcd(a,b)=gcd(b,amodb)。
算法来自于这个定理
两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。
证明
a可以表示成
a
=
k
b
+
r
a = kb + r
a=kb+r(a,b,k,r皆为正整数,且r<b),则
r
=
a
m
o
d
b
r = a \bmod b
r=amodb
假设d是a,b的一个公约数,记作 d ∣ a , d ∣ b d|a , d|b d∣a,d∣b,即a和b都可以被d整除。
而 r = a − k b r = a - kb r=a−kb,两边同时除以d, r / d = a / d − k b / d = m r/d=a/d-kb/d=m r/d=a/d−kb/d=m,由 a / d − k b / d = m a/d-kb/d=m a/d−kb/d=m可知m为整数,因此 d ∣ r d|r d∣r
因此d也是 b , a m o d b b,a \bmod b b,amodb的公约数
再假设一个新的
d
d
d是
b
,
a
m
o
d
b
b,a \bmod b
b,amodb的公约数, 则
d
∣
b
,
d
∣
(
a
−
k
∗
b
)
,
k
d|b,d|(a-k*b),k
d∣b,d∣(a−k∗b),k 是一个整数。
进而
d
∣
a
d|a
d∣a.因此d也是a,b的公约数
因此 ( a , b ) (a,b) (a,b)和 ( b , a m o d b ) (b,a \bmod b) (b,amodb)的公约数是一样的,其最大公约数也必然相等,得证。
代码
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
if (a < b) swap(a, b);
return b == 0 ? a : gcd(b, a % b);
}
int x, y;
int main(){
cin >> x >> y;
cout << gcd(x, y);
return 0;
}
扩展欧几里得
贝祖定理: 若 a , b 是 整 数 , 且 g c d ( a , b ) = d , 那 么 对 于 任 意 的 整 数 x , y , a x + b y = m 中 的 m 一 定 是 d 的 倍 数 。 特 别 地 , 如 果 a 、 b 是 整 数 , 那 么 一 定 存 在 整 数 x 、 y 使 得 a x + b y = g c d ( a , b ) 若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by=m中的m一定是d的倍数。特别地,如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b) 若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by=m中的m一定是d的倍数。特别地,如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)
证明:
欧几里得算法,它总是把gcd(a,b)转化为求解gcd(b,a%b),而当b变为0时返回a,此时的a就等于gcd。也就是说,欧几里得算法结束时变量a中存放的是gcd,变量b中存放的是0,因此此时显然有a×1+b×0=gcd成立,此时有x=1,y=0成立。
我们不妨利用上面的欧几里得算法的过程来计算x和y。目前已知的是递归边界成立时为x=1、y=0,需要想办法反推出最初始的x和y。
当计算 g c d ( a , b ) gcd(a,b) gcd(a,b)时,有 a x 1 + b x 1 = g c d ax1+bx1=gcd ax1+bx1=gcd成立。
而在下一步计算 g c d ( b , a m o d b ) gcd(b,a \bmod b) gcd(b,amodb) 时,又有 b x 2 + ( a m o d b ) y 2 = g c d bx2+(a \bmod b)y2=gcd bx2+(amodb)y2=gcd成立。
因此 a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 ax1+by1=bx2+(a \bmod b)y2 ax1+by1=bx2+(amodb)y2成立。
又考虑到有关系 a m o d b = a − ( a / b ) × b a \bmod b=a−(a/b)×b amodb=a−(a/b)×b成立(此处除法为整除),代入有 a x 1 + b y 1 = a y 1 + b ( x 2 − ( a / b ) y 2 ) ax1+by1=ay1+b(x2−(a/b)y2) ax1+by1=ay1+b(x2−(a/b)y2)
对比等号左右两边,有如下关系
f
(
x
)
=
{
x
1
=
y
2
y
1
=
x
2
−
(
a
/
b
)
y
2
f(x)=\left\{ \begin{aligned} x1 & = y2 \\ y1 & =x2-(a / b)y2 \end{aligned} \right.
f(x)={x1y1=y2=x2−(a/b)y2
此我们便可以通过x2和y2
来进行反推出x1y1了
int exGcd(int a, int b, int &x, int &y) //x和y使用引用
{
if(b==0)
{
x=1;
y=0;
return a;
}
int g=exGcd(b,a%b,x,y); //递归计算exGcd(b,a%b)
int temp=x; //存放x的值
x=y;
y=temp-(a/b)*y; //更新y = x(old) - a/b*y(old)
return g; //g是gcd
}
由于这里我们使用了引用,因此当exGcd函数结束时x和y就是所求的解。
显然,在得到这样一组解之后,就可以通过下面的式子得到全部解(其中K为任意整数):
f
(
x
)
=
{
x
′
=
x
+
b
/
g
c
d
∗
k
y
′
=
y
−
a
/
g
c
d
∗
k
f(x)=\left\{ \begin{aligned} x' & =x+b/{gcd}*k \\ y' & =y-a/gcd*k \end{aligned} \right.
f(x)={x′y′=x+b/gcd∗k=y−a/gcd∗k
原文有证明,我这里就不写了,大家有疑惑可以看原文。
方程ax+by=c的求解
首先,假设
a
x
+
b
y
=
g
c
d
ax+by=gcd
ax+by=gcd有一组解
(
x
0
,
y
0
)
(x0,y0)
(x0,y0),
a
∗
x
0
+
b
∗
y
0
=
g
c
d
a*x0+b*y0=gcd
a∗x0+b∗y0=gcd
现在在其等号的左右两边同时乘以
c
/
g
c
d
c/gcd
c/gcd
即有
a
∗
c
∗
x
0
/
g
c
d
+
b
∗
c
∗
y
0
/
g
c
d
=
c
a*c*x0/gcd+b*c*y0/gcd=c
a∗c∗x0/gcd+b∗c∗y0/gcd=c
成立,
因此
(
x
,
y
)
=
(
c
x
0
/
g
c
d
,
c
y
0
/
g
c
d
)
(x,y)=(cx0/gcd,cy0/gcd)
(x,y)=(cx0/gcd,cy0/gcd)是
a
x
+
b
y
=
c
ax+by=c
ax+by=c的一组解。
但是显然这样做的充要条件是
c
m
o
d
g
c
d
=
0
c \bmod {gcd}=0
cmodgcd=0(因为:
a
∗
x
/
g
c
d
+
b
∗
y
/
g
c
d
=
c
/
g
c
d
a*x/gcd+b*y/gcd=c/gcd
a∗x/gcd+b∗y/gcd=c/gcd(其中左边为整数因此右边也为整数)
否则第一步将无法做到。
求全部解的方式类似于上面,不明白的读者可以自行查阅原文,这里不再赘述。
3.同余式ax≡c(mod m)的解
a
x
≡
c
(
m
o
d
m
)
ax≡c(mod m)
ax≡c(modm) 就是
a
x
=
m
y
+
c
ax=my+c
ax=my+c
a
x
−
m
y
=
c
ax-my=c
ax−my=c
设
y
=
−
y
y=-y
y=−y
有
a
x
+
m
y
=
c
ax+my=c
ax+my=c
转化成为了上面的问题,全部解同样可以查询原文 (因为我说我懒实在是不好意思)
4.逆元的求解
逆元就是
设
a
,
b
,
m
a,b,m
a,b,m为整数,
a
∗
b
≡
1
(
m
o
d
m
)
a*b≡1(mod m)
a∗b≡1(modm)
那么a与b互为模m的逆元
由定义知,求a模m的逆元,就是求解同余式
a
x
≡
1
(
m
o
d
m
)
ax≡1(mod m)
ax≡1(modm),并且在实际使用中,一般把x的最小正整数解称为a模m的逆元.
又转化为上面的问题。
抄的代码
int inverse(int a,int m)
{
int x, y;
int g = exGcd(a, m, x, y); //求解ax+my=1
return (x%m+m)%m; //a模m的逆元为(x%m+m)%m
}