欧几里得算(辗转相除法)
算法描述
设 a>=b
a
÷
b
=
k
⋅
⋅
⋅
⋅
⋅
⋅
r
a \div b = k ······ r
a÷b=k⋅⋅⋅⋅⋅⋅r
a和b的最大公约数等于b和r的最大公约数。
gcd(a,b)=gcd(b,a%b),当b为0时,a为(a,b)最大公约数
C++实现
//递归方式
int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
//非递归方式
while(b!=0)
{
int r=a%b;
a=b;
b=r;
}
cout<<a;
定理证明
- 证明a,b的公约数和 b,r的公约数相同,就能证明最大公约数相同
- 设a = kb+r (a>=b)。由假设可知,r=a mod b。
- 设d为a和b的任意公约数。
- 变形可得到式子:r=a-kb,等式两边同除d,可得到式子: r/d = a/d - kb/d =m。
- 因为d为a,b的公约数,故a/d 为整数,b/d为整数,故r/d也为整数,可推出d为r的约数。故d是b和r的约数。
- 所以,a和b的任意公约数d,也是b和a%b的公约数。
- 设 d 是 b,a%b的公约数,则d是b和a-kb的公约数
- 设b=xd, a-kb=yd(d是他们的约数,他们则可写成d的倍数形式)。则存在a=kb+yd;
- 将等式两边同除d,a/d =kb/d + y=m。y是整数,d是b的约数,所以m未整数,即d是a的约数。
- 所以d也是a和b的公约数
- 综上,(a,b)和(b,a%b)的公约数集合相同,证得(a,b)和(b,a%b)的公约数是一样的
- 所以最大公约数也相同,证明gcd(a,b)=gcd(b,a%b)
拓展欧几里得算法
定理:
给予两个整数a、b,必存在整数x,y使得ax + by = gcd(a,b)。(贝祖等式)
拓展欧几里得算法就是再辗转相除法的基础上,求的改等式的通解。
x=x0+(b/gcd(a,b)) * t
y=y0-(a/gcd(a,b)) * t
我们知道:a%b = a - (a/b) * b,所以我可以进一步得到
gcd(a,b) = gcd(b, a%b) :
gcd(a%b)=b * x1 + ( a - (a/b)* b)* y1
=b x1 + ay1-(a/b)by1
= a * y1 +b*(x1-a/by1)
观察可以发现,x=y1,y=x1-a/b y1
所以我们只要在求解欧几里得的时候同时加上对x,y的更新即可。考虑边界情况,当b=0时,显然此时x=1,y=0;
代码实现
int ex_gcd(int a,int b,int &x,int &y)
{
if(b==0) {x=1;y=0;return a;}
int ans=ex_gcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return ans;
}
//精简
int ex_gcd(int a,int b,int &x,int &y)
{
if(b==0) {x=1;y=0;return a;}
int ans=ex_gcd(b,a%b,y,x);
y-=(a/b)*x;
return ans;
}