欧几里得:
实际上就是辗转相除法求最大公约数。
给定一个a,b,求他们的最大公约数(gcd)
辗转相除法是:(一般a>b)
gcd(a,b)
第一轮:a%b=a2a\%b=a_2a%b=a2
此时gcd(b,a2a_2a2)
第二轮:b%a2=a3b\%a_2=a_3b%a2=a3
直到gcd(x,0),答案为x.
举例:
gcd(48, 18)
48 ÷ 18 = 2 余 12 → gcd(18, 12)
18 ÷ 12 = 1 余 6 → gcd(12, 6)
12 ÷ 6 = 2 余 0 → gcd(6, 0)
b=0 → 结果 = 6
代码:
cpp
int gcd(int a,int b)
{
if(b)
return gcd(b,a%b);
else
return a;
}
扩展欧几里得:
简单来说就是带记录的欧几里得。
形如:ax+by=gcd(a,b)ax + by = gcd(a ,b)ax+by=gcd(a,b)
计算gcd的同时,会记录出对应的(x ,y);
由欧几里得可知:
gcd(a,b)=gcd(b,a%b)gcd(a,b)=gcd(b ,a\%b)gcd(a,b)=gcd(b,a%b)
由整除法可得:
a%b=a−⌊a/b⌋∗ba\%b=a - \lfloor a/b \rfloor*ba%b=a−⌊a/b⌋∗b
带入上式,整理可得:
ay1+b(x1−⌊a/b⌋∗y1)=gcd(a,b)ay_1 +b(x_1 - \lfloor a/b \rfloor * y_1) = gcd(a,b)ay1+b(x1−⌊a/b⌋∗y1)=gcd(a,b)
联立原式:
x=y1y=x1−⌊a/b⌋∗y1x=y1\quad y=x_1-\lfloor a/b \rfloor*y_1x=y1y=x1−⌊a/b⌋∗y1
当b==0时:
x=1y=0x=1\quad y=0x=1y=0
代码:
cpp
int exgcd(int a,int b,int &x,int &y)
{
if(b==0){
x=1,y=0;
return a;
}
int x1,y1;
int d=exgcd(b,a%b,x1,y1);
x=y1;
y=x1-(a/b)*y1;
}
exgcd(b,a%b,y,x)exgcd(b, a\%b, y, x)exgcd(b,a%b,y,x)调用时,y 接收了递归的 x1,x 接收了递归的 y1
然后只需要 y−=a/b∗xy -= a/b * xy−=a/b∗x就完成了 y=x1−(a/b)∗y1y = x1 - (a/b)*y1y=x1−(a/b)∗y1
整理简化得:
cpp
int exgcd(int a,int b,int &x,int &y)
{
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
}