[知识点] 6.4.2 欧几里得算法与扩欧算法

总目录 > 6 数学 > 6.4 数论 > 6.4.2 欧几里得算法与扩欧算法

前言

没什么好说的啦。

更新日志

Update - 20200728

重整了一下章节之间的逻辑,以及标题进行了替换。

子目录列表

1、欧几里得算法

2、扩欧算法

3、求解

4、应用

6.4.2 欧几里得算法与扩欧算法

1、欧几里得算法

欧几里得算法(Euclidean Algorithm),又称为辗转相除法,用于计算两个正整数 x, y 的最大公约数,公式为:

gcd(x, y) = gcd(y, x mod y)

代码:

1 int gcd(int x, int y) {
2     return y ? gcd(y, x % y) : x; 
3 }

同时,你也可以选择使用 algorithm 库中的 __gcd(x, y) 函数。

2、扩欧算法

扩展欧几里得算法(Extended Euclidean algorithm)是欧几里得算法的扩展版本,简称扩欧算法。已知正整数 a, b,求得最大公约数的同时可以求得 x, y(其中一个很可能为负数),使它们满足裴蜀定理

ax + by = gcd(a, b)

3、扩欧求解

求解方法和欧几里得算法类似,在辗转相除的基础上增加两个数组,具体步骤见下:

i = 5时,s[i] = -9, t[i] = 47,分别为裴蜀定理中的 x 和 y;余数r[i]为最大公约数。

i = 6时,s[i] = 23, t[i] = -120,用于验证正确性,验证方法:t[i] * (-2) = 240, s[i] * 2 = 46,分别为 a 和 b。 

代码 1:

1 int exgcd(int a, int b) {
2     if (!b) return ob;
3     x = oox - a / b * ox, oox = ox, ox = x;
4     y = ooy - a / b * oy, ooy = oy, oy = y;
5     return exgcd(ob = b, a % b);
6 }

(最终的 x 存放在 oox 中,y 同理)

这是根据算法的描述自己写的代码,在参考了更多 wiki 和博客的介绍后,发现 x 和 y 并不需要弄这么多变量来存,而可以先求得最大公约数后反推 x 和 y。

代码 2:

1 int exgcd(int a, int b, int &x, int &y) {
2     if (!b) {
3         x = 1, y = 0;
4         return a;
5     }
6     int res = exgcd(b, a % b, x, y);
7     ox = x, x = y, y = ox - a / b * y;
8     return res;
9 }

4、扩欧应用

① 求线性同余方程

线性同余方程形如  的方程。

由于方程和 ax + by = c 是等价的,根据扩展欧几里得定理,存在整数解等价于 gcd(a, b) 整除 c(gcd(a, b) | c)。

所以,根据上述求解方法求得 x 和 y 后,方程两边同时除以 gcd(a, b) 且乘 c,即 cx / gcd(a, b)和cy / gcd(a, b) 为方程的一组解。                

(gcd(a, b) = 1,且 x0, y0 为其中一组解时,所有解可以表示为 x = x0 + bt, y = y0 - at,t 为任意整数)

代码略。

② 求乘法逆元

乘法逆元全称为模意义下的乘法运算的逆元(Modular Multiplicative Inverse),如果一个线性同余方程满足:

则 x 称为 a mod b 的逆元,记作a ^ -1。

作为线性同余方程的一种特殊情况,思路是类似的:方程和 ax + by = 1 是等价的,存在整数解等价于 gcd(a, b) 整除 1,即 gcd(a, b) = 1,即 a 和 b 互素

代码略。

乘法逆元同样可以用费马小定理来求,请参见:6.4.3 费马小定理

原文地址:https://www.cnblogs.com/jinkun113/p/12525731.html