欧几里得算法及其扩展
欧几里得算法(即辗转相除法, GCD),求 a 和 b 的最大公约数(greatest common divisor)。
参考代码:
int gcd(int a, int b){
return (b == 0)? a:gcd(b, a%b);
}
裴蜀(贝祖)等式
对于任何整数 a , b 和它们的最大公倍数 d,关于未知数 x 和 y 的线性丢番图方程(称为裴蜀等式)。
ax + by = m
上述方程有整数解时当且仅当 m 是 d 的倍数。
裴蜀等式有解时必然有无穷多个整数解,每组解 x,y 都称为裴蜀数,
可用扩展欧几里得算法(Extended Euclidean algorithm)求得。
特别的,方程 ax + by = 1 有整数解当且仅当 a, b 互素。
拓展欧几里得算法
求 a, b 的最大公约数 m = gcd(a, b)的同时求出贝祖等式 ax + by = m 的一个解(x0, y0)。
设 k = a % b,则 a = bx + k = b * (a/b) +k ==> a%b = a - b * (a/b)
这里的除号 “/” 指的是计算机中不保留小数的除法。
我们要求的是 a * x + b * y = gcd = m
下一个状态是 b * x1 + (a%b) * y1 = gcd = m
把 a % b 代入:
gcd = b * x + (a - (a/b) * b) * y1
= b * x + a * y1 - (a/b) * b * y1
= a * y1 + b * (x1 - a/b *y1)
因此,得到递推式:x = y1 y = x1 - a/b * y1
上面的情况正好是 ax + by = gcd
若是求 ax + by = m 且 m % gcd = 0,则特解(x0, y0)需要乘以倍数 m/gcd。
通解:
x = x0 + (b/gcd) * t
y = y0 - (a/gcd) * t
如果想要得到 x > 0 的第一个解,则 b /= gcd x = (x0%b+b)%b
(此时 b 就是 x 的变化量)
(x % b 之后 |x0| < b,但无法保证 x > 0,所以要加上 b 保证 x > 0,但又不保证 < b,故再一次取模)
参考代码:
// 拓展欧几里得算法模板
int extendGCD(int a, int b){
// 最后一层的返回条件,此时a就是gcd
if(b == 0){
x = 1;
y = 0;
return a;
}
// res的结果始终是gcd,不会改变
int res = extendGCD(b, a%b);
// 进行过上一步之后,此时x和y已经是下一层的结果了
int x1 = x;
x = y;
y = x1 - a/b*y;
return res;
}
【END】感谢观看