最大公约数(gcd)算法

求最大公约数有两种算法, 欧几里得算法和更相减损法, 这里只讨论欧几里得算法
算法核心gcd(a,b)=gcd(b,amod b)\gcd(a, b) = \gcd(b, a \mod b)gcd(a,b)=gcd(b,amodb)
算法证明
引理: d ∣ ad \; | \; ad∣a并且d ∣ bd \; | \; bd∣b, 那么x,y,∈Zx, y, \in Zx,y,∈Z情况下, d ∣ ax+byd \; | \; ax + byd∣ax+by
证明:
由 d∣a,可设 a=d⋅m(m∈Z)由 d∣b,可设 b=d⋅n(n∈Z)那么:ax+by=(d⋅m)x+(d⋅n)y=d(mx+ny)因为 m,n,x,y∈Z,所以 mx+ny∈Z因此 d∣(ax+by) \begin{aligned} &\text{由 } d \mid a \text{,可设 } a = d \cdot m \quad (m \in \mathbb{Z}) \\ &\text{由 } d \mid b \text{,可设 } b = d \cdot n \quad (n \in \mathbb{Z}) \\ &\text{那么:} \\ &ax + by = (d \cdot m)x + (d \cdot n)y = d(mx + ny) \\ &\text{因为 } m, n, x, y \in \mathbb{Z} \text{,所以 } mx + ny \in \mathbb{Z} \\ &\text{因此 } d \mid (ax + by) \end{aligned} 由 d∣a,可设 a=d⋅m(m∈Z)由 d∣b,可设 b=d⋅n(n∈Z)那么:ax+by=(d⋅m)x+(d⋅n)y=d(mx+ny)因为 m,n,x,y∈Z,所以 mx+ny∈Z因此 d∣(ax+by)
证毕
根据上述引理, 证明欧几里得算法, 假设u=gcd(a,b)u = \gcd(a, b)u=gcd(a,b), v=gcd(b,amod b)v = \gcd(b, a \mod b)v=gcd(b,amodb), 证明u=vu = vu=v只需要证明 uuu能推出vvv并且vvv能推出uuu
首先证明uuu推出vvv
证明:
假设最大公约数是ddd, 因为d ∣ bd \; | \; bd∣b, 因此等式右边d ∣ bd \; | \; bd∣b就是正确的
还需要证明d ∣ (amod b)d \; | \; (a \mod b)d∣(amodb)
将amod ba \mod bamodb展开
amod b=a−⌊ab⌋⋅b a \mod b = a - \left \lfloor \frac{a}{b} \right \rfloor \cdot bamodb=a−⌊ba⌋⋅b
因为引理说明了d ∣ ax+byd \; | \; ax + byd∣ax+by, 将xxx设为111, yyy设为⌊ab⌋\left \lfloor \frac{a}{b} \right \rfloor⌊ba⌋
得到d ∣ a−⌊ab⌋⋅bd \; | \; a - \left \lfloor \frac{a}{b} \right \rfloor \cdot bd∣a−⌊ba⌋⋅b
也就是说d ∣ (amod b)d \; | \; (a \mod b)d∣(amodb)
uuu能推出vvv
再证明vvv推出uuu
证明:
设最大公约数是ddd, 由vvv可知, d ∣ bd \; | \; bd∣b, 因此等式左边d ∣ bd \; | \; bd∣b就是正确的
还需要证明d ∣ ad \; | \; ad∣a
由引理可知d ∣ ax+byd \; | \; ax + byd∣ax+by
将vvv展开
d ∣ bx+(amod b)yd \; | \; bx + (a \mod b)yd∣bx+(amodb)y
继续展开
d ∣ bx+(a−⌊ab⌋⋅b)yd \; | \; bx + (a - \left \lfloor \frac{a}{b} \right \rfloor \cdot b)yd∣bx+(a−⌊ba⌋⋅b)y
令x=⌊ab⌋x = \left \lfloor \frac{a}{b} \right \rfloorx=⌊ba⌋, y=1y = 1y=1, 得到
d ∣ b⋅(x−⌊ab⌋)+a d \; | \; b\cdot (x - \left \lfloor \frac{a}{b} \right \rfloor) + ad∣b⋅(x−⌊ba⌋)+a
化简得到
d ∣ ad \; | \; ad∣a
vvv能推出uuu
因为uuu能推出vvv并且vvv能推出uuu, 所以u=vu = vu=v, 证毕
欧几里得算法时间复杂度O(logk)O(\log k)O(logk)
代码实现
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
while (n--) {
int a, b;
cin >> a >> b;
cout << gcd(a, b) << '\n';
}
return 0;
}

京公网安备 11010502036488号