1. 基础概念
1.1 欧几里德算法(辗转相除法)
欧几里德算法用于计算两个整数的最大公约数(GCD)。其核心思想是:
gcd(a,b)=gcd(b,a mod b)\gcd(a,b) = \gcd(b, a \bmod b)gcd(a,b)=gcd(b,amodb)
递归实现:
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
迭代实现:
int gcd_iterative(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
1.2 裴蜀定理(Bézout’s Identity)
扩展欧几里德算法的理论基础是裴蜀定理:
对于任意整数a和b,存在整数x和y,使得:
ax+by=gcd(a,b)ax + by = \gcd(a,b)ax+by=gcd(a,b)
2. 扩展欧几里德算法原理
2.1 算法思想
在计算gcd(a,b)的同时,求解方程ax+by=gcd(a,b)ax + by = \gcd(a,b)ax+by=gcd(a,b)的整数解(x,y)。
2.2 递推关系
设gcd(a,b)=gcd(b,a mod b)\gcd(a,b) = \gcd(b, a \bmod b)gcd(a,b)=gcd(b,amodb)
假设已知:
b⋅x1+(a mod b)⋅y1=gcd(b,a mod b)b \cdot x_1 + (a \bmod b) \cdot y_1 = \gcd(b, a \bmod b)b⋅x1+(amodb)⋅y1=gcd(b,amodb)
由于a mod b=a−⌊a/b⌋⋅ba \bmod b = a - \lfloor a/b \rfloor \cdot bamodb=a−⌊a/b⌋⋅b,代入得:
b⋅x1+(a−⌊a/b⌋⋅b)⋅y1=gcd(a,b)b \cdot x_1 + (a - \lfloor a/b \rfloor \cdot b) \cdot y_1 = \gcd(a,b)b⋅x1+(a−⌊a/b⌋⋅b)⋅y1=gcd(a,b)
a⋅y1+b⋅(x1−⌊a/b⌋⋅y1)=gcd(a,b)a \cdot y_1 + b \cdot (x_1 - \lfloor a/b \rfloor \cdot y_1) = \gcd(a,b)a⋅y1+b⋅(x1−⌊a/b⌋⋅y1)=gcd(a,b)
因此:
- x=y1x = y_1x=y1
- y=x1−⌊a/b⌋⋅y1y = x_1 - \lfloor a/b \rfloor \cdot y_1y=x1−⌊a/b⌋⋅y1
2.3 边界条件
当b=0b = 0b=0时,gcd(a,0)=a\gcd(a,0) = agcd(a,0)=a,此时解为x=1,y=0x = 1, y = 0x=1,y=0。
3. C++实现
3.1 递归实现
#include <iostream>
#include <tuple>
using namespace std;
// 返回 (gcd, x, y)
tuple<int, int, int> extended_gcd(int a, int b) {
// 边界条件
if (b == 0) {
return make_tuple(a, 1, 0);
}
// 递归计算
auto [g, x1, y1] = extended_gcd(b, a % b);
// 回溯求解
int x = y1;
int y = x1 - (a / b) * y1;
return make_tuple(g, x, y);
}
3.2 迭代实现
tuple<int, int, int> extended_gcd_iterative(int a, int b) {
int x = 1, y = 0;
int x1 = 0, y1 = 1;
int a1 = a, b1 = b;
while (b1 != 0) {
int q = a1 / b1;
tie(x, x1) = make_tuple(x1, x - q * x1);
tie(y, y1) = make_tuple(y1, y - q * y1);
tie(a1, b1) = make_tuple(b1, a1 - q * b1);
}
return make_tuple(a1, x, y);
}
3.3 完整的扩展欧几里德类
class ExtendedEuclidean {
public:
// 结构体存储结果
struct Result {
int gcd, x, y;
Result(int g, int x_val, int y_val) : gcd(g), x(x_val), y(y_val) {}
};
// 递归版本
static Result solve_recursive(int a, int b) {
if (b == 0) {
return Result(a, 1, 0);
}
Result sub_result = solve_recursive(b, a % b);
int x = sub_result.y;
int y = sub_result.x - (a / b) * sub_result.y;
return Result(sub_result.gcd, x, y);
}
// 迭代版本
static Result solve_iterative(int a, int b) {
int x = 1, y = 0;
int x1 = 0, y1 = 1;
while (b != 0) {
int q = a / b;
int temp_x = x;
int temp_y = y;
x = x1;
y = y1;
x1 = temp_x - q * x1;
y1 = temp_y - q * y1;
int temp = a;
a = b;
b = temp % b;
}
return Result(a, x, y);
}
// 验证结果
static bool verify(int a, int b, const Result& result) {
return a * result.x + b * result.y == result.gcd;
}
};
4. 算法演示
4.1 手动计算示例
求解gcd(30,18)\gcd(30, 18)gcd(30,18)及方程30x+18y=gcd(30,18)30x + 18y = \gcd(30,18)30x+18y=gcd(30,18)的解:
gcd(30, 18):
30 = 1×18 + 12
18 = 1×12 + 6
12 = 2×6 + 0
gcd = 6
回溯求解:
6 = 18 - 1×12
= 18 - 1×(30 - 1×18)
= -1×30 + 2×18
所以 x = -1, y = 2
验证:30×(-1) + 18×2 = -30 + 36 = 6 ✓
4.2 C++测试代码
void test_extended_gcd() {
int a = 30, b = 18;
// 递归版本
auto [g1, x1, y1] = extended_gcd(a, b);
cout << "递归: gcd(" << a << "," << b << ") = " << g1
<< ", x = " << x1 << ", y = " << y1 << endl;
cout << "验证: " << a << "×" << x1 << " + " << b << "×" << y1
<< " = " << a*x1 + b*y1 << endl;
// 迭代版本
auto [g2, x2, y2] = extended_gcd_iterative(a, b);
cout << "迭代: gcd(" << a << "," << b << ") = " << g2
<< ", x = " << x2 << ", y = " << y2 << endl;
cout << "验证: " << a << "×" << x2 << " + " << b << "×" << y2
<< " = " << a*x2 + b*y2 << endl;
}
输出:
递归: gcd(30,18) = 6, x = -1, y = 2
验证: 30×-1 + 18×2 = 6
迭代: gcd(30,18) = 6, x = -1, y = 2
验证: 30×-1 + 18×2 = 6
5. 重要应用
5.1 求解线性同余方程
方程ax≡b(modm)ax \equiv b \pmod{m}ax≡b(modm)有解当且仅当gcd(a,m)∣b\gcd(a,m) | bgcd(a,m)∣b。
求解步骤:
- 计算g=gcd(a,m)g = \gcd(a,m)g=gcd(a,m)
- 若g∤bg \nmid bg∤b,无解
- 否则,求ax′+my′=gax' + my' = gax′+my′=g的解
- 特解:x0=x′⋅(b/g)x_0 = x' \cdot (b/g)x0=x′⋅(b/g)
- 通解:x=x0+k⋅(m/g)x = x_0 + k \cdot (m/g)x=x0+k⋅(m/g)
vector<int> solve_linear_congruence(int a, int b, int m) {
auto [g, x, y] = extended_gcd(a, m);
if (b % g != 0) {
return {}; // 无解
}
int x0 = (x * (b / g)) % m;
if (x0 < 0) x0 += m;
vector<int> solutions;
for (int i = 0; i < g; i++) {
solutions.push_back((x0 + i * (m / g)) % m);
}
return solutions;
}
5.2 求模逆元
当gcd(a,m)=1\gcd(a,m) = 1gcd(a,m)=1时,a在模m下的逆元存在,即求解ax≡1(modm)ax \equiv 1 \pmod{m}ax≡1(modm)。
int mod_inverse(int a, int m) {
auto [g, x, y] = extended_gcd(a, m);
if (g != 1) {
throw runtime_error("模逆元不存在");
}
int inv = x % m;
if (inv < 0) inv += m;
return inv;
}
5.3 中国剩余定理
扩展欧几里德算法是中国剩余定理求解的基础。
6. 复杂度分析
- 时间复杂度:O(log min(a,b))
- 空间复杂度:O(1)(迭代版本),O(log min(a,b))(递归版本,栈空间)
7. 注意事项
- 整数溢出:大数运算时注意int溢出,可使用long long
- 负数处理:算法对负数同样适用,但需注意符号
- 解的范围:解不唯一,通常取最小非负解
- 边界情况:处理a=0或b=0的情况
8. 完整测试示例
int main() {
// 测试基本功能
auto result = ExtendedEuclidean::solve_iterative(120, 23);
cout << "gcd(120,23) = " << result.gcd
<< ", x = " << result.x << ", y = " << result.y << endl;
// 验证
cout << "验证: 120×" << result.x << " + 23×" << result.y
<< " = " << 120*result.x + 23*result.y << endl;
// 求模逆元
try {
int inv = mod_inverse(7, 26);
cout << "7在模26下的逆元: " << inv << endl;
cout << "验证: 7×" << inv << " mod 26 = " << (7*inv) % 26 << endl;
} catch (const exception& e) {
cout << e.what() << endl;
}
return 0;
}
9. 总结
扩展欧几里德算法不仅计算最大公约数,还求解裴蜀等式,是数论和密码学中的基础算法。迭代实现效率更高,推荐在实际应用中使用。算法在求解线性同余方程、模逆元、中国剩余定理等方面有重要应用。
1117

被折叠的 条评论
为什么被折叠?



