欧几里得算法(辗转相除法)的原理(点击这里)就可以解决。
对于任意的正整数a, b, 都有
a = k b + r ( k , r ∈ N ) a = kb + r\ (k,\ r \in\ N) a=kb+r (k, r∈ N)
r = a % b r = a\ \%\ \ b r=a % b
假设 c 为a, b的最大公约数
c = g c d ( a , b ) c = gcd(a, b) c=gcd(a,b)
∴ c ∣ a , c ∣ b \therefore \ c|a, c | b ∴ c∣a,c∣b
( c ∣ a = a c|a = a c∣a=a可以整除以 c c c)
∵ r = a − k b \because r = a - kb ∵r=a−kb
∴ c ∣ r \therefore c | r ∴c∣r
∴ c = g c d ( b , r ) \therefore c = gcd(b, r) ∴c=gcd(b,r)
结论: g c d ( a , b ) = g c d ( b , a % b ) gcd(a, b) = gcd(b, a\ \%\ b ) gcd(a,b)=gcd(b,a % b)
递归版本:
int gcd(int a,int b) {
return b ? gcd(b, a % b) : a;
}
非递归(迭代)版本:
int gcd(int a, int b) {
while (b) {
a = a % b;
swap(a, b);
}
return a;
}
顺便安利一波求最小公倍数的代码
int lcm(int a, int b) {
return a / gcd(a, b) * b; //先除后乘可以防止溢出
}
简单来讲,就是求解贝祖等式的解(注意求解出来的x,y不是最小的整数解)形如
a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b)
a , b ∈ N a, b \in N a,b∈N
证明:
当 b = 0 b = 0 b=0 时,等式为 a x + 0 ∗ y = g c d ( a , 0 ) ax + 0 * y = gcd (a, 0) ax+0∗y=gcd(a,0)
∴ a x = a \therefore ax = a ∴ax=a
∴ x = 1 \therefore x = 1 ∴x=1
此时 y y y 我们令它为 0 0 0
也就是 x = 1, y = 0
a x 1 + b y 1 = g c d ( a , b ) ax_1 + by_1 = gcd(a, b) ax1+by1=gcd(a,b)
b x 2 + ( a % b ) y 2 = g c d ( a , b ) bx_2 + (a\ \%\ b) y_2 = gcd(a, b) bx2+(a % b)y2=gcd(a,b)
根据欧拉几得算法又得出 : g c d ( a , b ) = g c d ( b , a % b ) gcd (a, b) = gcd (b, a\ \%\ b) gcd(a,b)=gcd(b,a % b)
∴ a x 1 + b y 1 = b x 2 + ( a % b ) y 2 \therefore ax_1 + by_1 = bx_2 + (a\ \%\ b) y_2 ∴ax1+by1=bx2+(a % b)y2
∵ a % b = a − a / b ∗ b \because a\ \%\ b = a - a / b * b ∵a % b=a−a/b∗b
∴ a x 1 + b y 1 = b x 2 + ( a − a / b ∗ b ) y 2 \therefore ax_1 + by_1 = bx_2 + (a - a / b * b) y_2 ∴ax1+by1=bx2+(a−a/b∗b)y2
∴ a x 1 + b y 1 = b x 2 + a y 2 − ( a / b ∗ b ) y 2 \therefore ax_1 + by_1 = bx_2 + ay_2 - (a / b * b ) y_2 ∴ax1+by1=bx2+ay2−(a/b∗b)y2
∴ a x 1 + b y 1 = a y 2 + b ( x 2 − a / b ∗ y 2 ) \therefore ax_1 + by_1 = ay_2 + b(x_2 - a / b * y_2) ∴ax1+by1=ay2+b(x2−a/b∗y2)
∴ x 1 = y 2 \therefore x_1 = y_2 ∴x1=y2
∴ y 1 = x 2 − a / b ∗ y 2 \therefore y_1 = x_2 - a / b * y_2 ∴y1=x2−a/b∗y2
接下来的步骤直接递归就好了
代码实现:
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int tx, ty;
int res = exgcd(b, a % b, tx, ty);
x = ty;
y = tx - a / b * ty;
return res;
}
简化版
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int res = exgcd(b, a % b, y, x);
y -= a / b * x;
return res;
}