【数论】扩展欧几里德算法

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)bx1+(amodb)y1=gcd(b,amodb)

由于a mod b=a−⌊a/b⌋⋅ba \bmod b = a - \lfloor a/b \rfloor \cdot bamodb=aa/bb,代入得:
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)bx1+(aa/bb)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)ay1+b(x1a/by1)=gcd(a,b)

因此:

  • x=y1x = y_1x=y1
  • y=x1−⌊a/b⌋⋅y1y = x_1 - \lfloor a/b \rfloor \cdot y_1y=x1a/by1

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}axb(modm)有解当且仅当gcd⁡(a,m)∣b\gcd(a,m) | bgcd(a,m)b

求解步骤

  1. 计算g=gcd⁡(a,m)g = \gcd(a,m)g=gcd(a,m)
  2. g∤bg \nmid bgb,无解
  3. 否则,求ax′+my′=gax' + my' = gax+my=g的解
  4. 特解:x0=x′⋅(b/g)x_0 = x' \cdot (b/g)x0=x(b/g)
  5. 通解: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}ax1(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. 注意事项

  1. 整数溢出:大数运算时注意int溢出,可使用long long
  2. 负数处理:算法对负数同样适用,但需注意符号
  3. 解的范围:解不唯一,通常取最小非负解
  4. 边界情况:处理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. 总结

扩展欧几里德算法不仅计算最大公约数,还求解裴蜀等式,是数论和密码学中的基础算法。迭代实现效率更高,推荐在实际应用中使用。算法在求解线性同余方程、模逆元、中国剩余定理等方面有重要应用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值