欧几里得算法,又称辗转相除法,是一种用来求两个正整数最大公约数(GCD)的古老且高效的算法。该算法基于一个基本的数学原理:两个数的最大公约数不变,即使一个数被另一个数的余数替换之后。
这个算法由古希腊数学家欧几里得在《几何原本》中首次描述,至今已有超过两千年的历史,是已知最古老的算法之一。
欧几里得算法可以描述为以下步骤:
以下是使用递归方式实现的欧几里得算法:
1#include<iostream>
2using namespace std;
3
4int gcd(int a, int b) {
5 if (b == 0) {
6 return a;
7 }
8 return gcd(b, a % b);
9}
10
11int main() {
12 int n = 0;
13 int m = 0;
14 while (true) {
15 cin >> n >> m;
16 cout << gcd(n, m) << endl;
17 }
18 return 0;
19}假设需要计算 252 和 105 的最大公约数:
余数为 0,此时除数为 21,因此最大公约数是 21。
执行示例: 以计算 gcd(462, 180) 为例,展示递归调用过程:
1gcd(462, 180)
2 → b=180 ≠ 0,计算 462 % 180 = 102
3 → 调用 gcd(180, 102)
4 → b=102 ≠ 0,计算 180 % 102 = 78
5 → 调用 gcd(102, 78)
6 → b=78 ≠ 0,计算 102 % 78 = 24
7 → 调用 gcd(78, 24)
8 → b=24 ≠ 0,计算 78 % 24 = 6
9 → 调用 gcd(24, 6)
10 → b=6 ≠ 0,计算 24 % 6 = 0
11 → 调用 gcd(6, 0)
12 → b=0,返回 a=6
13 → 返回 6
14 → 返回 6
15 → 返回 6
16 → 返回 6
17 → 返回 6最终结果:gcd(462, 180) = 6
验证:462 = 6×77,180 = 6×30,而 gcd(77, 30) = 1,所以 6 确实是最大公约数。
欧几里得算法是高效的,特别适用于大数的最大公约数计算。它的时间复杂度大约是 O(log(min(a, b))),这使得即使对于非常大的数字,算法也能迅速收敛到结果。这种对数级别的复杂度来源于每次取模操作至少会将较大的数减半。
两个数 a 和 b 的最小公倍数公式为:lcm(a, b) = a / gcd(a, b) * b
注意先除后乘可以避免中间结果溢出。例如:
遇到求最大公约数或最小公倍数的问题时:
gcd(a, b) = (b == 0) ? a : gcd(b, a % b)。gcd(a, b, c) = gcd(gcd(a, b), c) 的性质,依次两两求 GCD。lcm = a / gcd * b。lcm(a, b, c) = lcm(lcm(a, b), c)。a % b = a,下一步自动变成 gcd(b, a),相当于自动交换了。b == 0 时返回 a,而不是 a == 0 时返回 b(虽然数学上等价,但与代码中的参数顺序要一致)。a b / gcd(a, b) 中 a b 可能超出 int 甚至 long long 的范围。应该写成 a / gcd(a, b) * b,先除后乘。a - b 代替 a % b,虽然正确但效率极低(想象 gcd(1000000, 1) 需要循环一百万次),实际编程中应该始终使用取模版本。