扩展欧几里得算法——exgcd

本文详细介绍了扩展欧几里德算法,一种用于解决贝祖等式ax+by=gcd(a,b)的方法。通过递归过程,算法不仅求解等式,还展示了如何利用其求解逆元,特别适用于模数非质数的情况。文章包含算法实现代码及逆元求解示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扩展欧几里德算法是用来在已知 a , b a,b a,b求解一组 x , y x,y x,y,使它们满足贝祖(裴蜀)等式: a x + b y = gcd ⁡ ( a , b ) = d ax+by = \gcd(a, b) =d ax+by=gcd(a,b)=d

关于贝祖等式

试着来搞一下

a x + b y = gcd ⁡ ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)

先考虑一下特殊情况,如果 b = 0 b=0 b=0,那么 gcd ⁡ ( a , b ) = a \gcd(a,b)=a gcd(a,b)=a,并显然存在一组解 x = 1 , y = 0 x=1,y=0 x=1,y=0

设当前的式子为 a x 1 + b y 1 = g c d ( a , b ) ax_1+by_1=gcd(a,b) ax1+by1=gcd(a,b),肯定存在式子 b x 2 + ( a   m o d   b ) y 2 = gcd ⁡ ( b , a   m o d   b ) bx_2+(a\bmod b)y_2=\gcd(b,a\bmod b) bx2+(amodb)y2=gcd(b,amodb)

根据欧几里得算法, gcd ⁡ ( a , b ) = gcd ⁡ ( b , a   m o d   b ) \gcd(a,b)=\gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)

∴ a x 1 + b y 1 = b x 2 + ( a   m o d   b ) y 2 \therefore ax_1+by_1=bx_2+(a\bmod b)y_2 ax1+by1=bx2+(amodb)y2

∵ a   m o d   b = a − a ÷ b × b \because a\bmod b=a-a\div b\times b amodb=aa÷b×b

∴ a x 1 + b y 1 = b x 2 + ( a − a ÷ b × b ) y 2 \therefore ax_1+by_1=bx_2+(a-a\div b\times b)y_2 ax1+by1=bx2+(aa÷b×b)y2
    a x 1 + b y 1 = b x 2 + a y 2 − a ÷ b × b × y 2 ax_1+by_1=bx_2+ay_2-a\div b\times b\times y_2 ax1+by1=bx2+ay2a÷b×b×y2
    a x 1 + b y 1 = a y 2 + b ( x 2 − a ÷ b × y 2 ) ax_1+by_1=ay_2+b(x_2-a\div b\times y_2) ax1+by1=ay2+b(x2a÷b×y2)

∴ x 1 = y 2 , y 1 = x 2 − a ÷ b × y 2 \therefore x_1=y_2,y_1=x_2-a\div b\times y2 x1=y2,y1=x2a÷b×y2

于是就可以愉快的递推下去了

代码很短:

int exgcd(int a,int b,long long &x,long long &y)
{
    if(b==0)return x=1,y=0,a;
    int d=exgcd(b,a%b,y,x);//d的值实际上就是gcd(a,b),如果不需要的话可以不求
    return y-=a/b*x,d;
}

顺便普及一下逗号运算符,:在C++中,(a,b,c)==c。也就是说,一堆表达式用逗号连接起来,他们的值就是最后一个表达式的值(巧妙的使用可以使得代码复杂度降低)


当然exgcd不可能只有这么点用途呀,它还可以用来求逆元,并且比用费马小定理求更方便,比如求 a a a 在模 p p p 意义下的逆元,如果用费马小定理求的话,还要保证 p p p 是个质数,但是用exgcd就不用了。

怎么求呢?

x x x a a a 在模 p p p 意义下的逆元,那么满足式子:
a x ≡ 1 ( m o d m ) ax \equiv 1\pmod m ax1(modm)

那么有:

a x + m y = 1 ax+my=1 ax+my=1

然后用 e x g c d exgcd exgcd 搞出 x x x 即可(以及这就是为什么 a a a m m m 一定要互质 才能使得 a a a 在模 m m m 意义下有逆元)

以及逆元的代码在此:

long long inv(long long a,long long m)
{
    long long x,y;
    long long d=exgcd(a,m,x,y);
    return d==1?(x+m)%m:-1;//不互质就没有逆元
}
### 扩展欧几里得算法(Extended Euclidean Algorithm) #### 定义与原理 扩展欧几里得算法是一种用于决形如 \( ax + by = \text{gcd}(a, b) \) 的线性不定方程的方法。它不仅能够计算两个整数 \( a \) \( b \) 的最大公约数 (\( \text{gcd} \)),还能找到满足上述等式的整数 \( x \) \( y \)[^2]。 此算法基于欧几里得算法的核心思想——辗转相除法,在此基础上进一步推导出系数 \( x \) \( y \),使得最终的结果满足给定的线性关系[^1]。 --- #### 算法实现 以下是扩展欧几里得算法的一个典型 C++ 实现: ```cpp #include <iostream> using namespace std; // 函数声明:返回 gcd(a, b),更新参数 x y 为对应 int extendedEuclid(int a, int b, int &x, int &y) { if (b == 0) { // 边界条件 x = 1; y = 0; return a; // 返回当前的最大公约数 } int gcd = extendedEuclid(b, a % b, x, y); int tempX = x; // 存储旧的 x 值 x = y; // 更新新的 x 值 y = tempX - (a / b) * y; // 计算新的 y 值 return gcd; // 返回最大公约数 } int main() { int a, b, x, y; cout << "请输入 a b:" << endl; cin >> a >> b; int gcdValue = extendedEuclid(a, b, x, y); // 调用扩展欧几里得算法 cout << "最大公约数为: " << gcdValue << endl; cout << "对应的 x y 是:" << endl; cout << "x = " << x << ", y = " << y << endl; return 0; } ``` 在这个实现中,`extendedEuclid` 函数通过递归调用来逐步缩小问题规模,直到达到边界条件 \( b = 0 \)。此时,\( a \) 即为两数的最大公约数,而初始设为 \( x = 1 \), \( y = 0 \)。随后,在回溯过程中不断调整 \( x \) \( y \) 的值,直至获得原问题的[^4]。 --- #### 应用场景 ##### 1. 线性同余方程 扩展欧几里得算法可用于求形式为 \( ax \equiv b \pmod{n} \) 的线性同余方程。这类方程有的前提是 \( \text{gcd}(a, n) \mid b \),即 \( b \) 必须能被 \( \text{gcd}(a, n) \) 整除[^3]。 一旦验证了可性,则可以通过扩展欧几里得算法先求出特 \( x_0 \),再利用通公式得出所有可能的集。 ##### 2. 密码学中的应用 在现代密码学领域,尤其是 RSA 加密体制的设计中,扩展欧几里得算法扮演着重要角色。具体来说,它帮助快速寻找模反元素(Modular Inverse),这是构建公钥加密体系的关键步骤之一。 例如,在生成私钥的过程中,需要计算某个整数相对于特定模数的乘法逆元,这正是扩展欧几里得算法擅长的任务。 --- #### 总结 综上所述,扩展欧几里得算法不仅是理论数学的重要工具,也是实际工程实践中不可或缺的技术手段。无论是处理简单的代数问题还是复杂的密码协议设计,其高效性可靠性都得到了广泛认可[^5]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值