扩展欧几里得算法及欧拉公式
扩展欧几里得算法及欧拉公式

扩展欧几里得算法及欧拉公式

欧几里得算法

欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。

整数 a, b 的最大公约数一般表示为 gcd(a, b)

gcd(a, b) = gcd(b, a % b)

代码示例:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;
// 当 a > b, 缩小问题规模的作用
// 当 a < b, 交换a, b位置的作用 
int gcd(int a, int b) {
    cout << "gcd(" << a << ", " << b << ") = ";
    if (b) return gcd(b, a % b);
    return a;
}

int main() {
    int a, b;
    while (cin >> a >> b) {
        cout << gcd(a, b) << endl;
    }
    return 0;
}

证明 1: b 和 a % b 的最大公约数,是 a 和 b 的公约数

  1. 设 b 和 a % b 的最大公约数为 C
  2. 则 b = y * C ① , a % b = x * C ②
  3. 由 ② 得 a – k * b = x * C ③
  4. 由 ①、③ 得 a = (x + k * y) * C ④
  5. 由 ①、④ 可得:C 也是 a 和 b 的公约数

证明 2: b 和 a % b 的最大公约数也是 a 和 b 的最大公约数

  1. 反证法:假设a和b的最大公约数不是C,是d
  2. 由 ①、④可知:gcd(x + k * y, y)= d,且 d 不等于 1
  3. 所以 x + k * y = m * d; y = n * d;
  4. 所以x = m * d – k * y = (m – k * n) * d; y = n * d;
  5. 即 x = (m – k * n) * d;y = n * d; 故 x 与 y 之间存在公约数d;
  6. 由于“b 和 a % b 的最大公约数为 C”及①、② 可知,x 与 y 之间没有公约数;
  7. 5 与 6 相悖,故 1 不成立。

扩展欧几里得算法

裴蜀定理

裴蜀定理说明了对任何整数 a、b和它们的最大公约数 d ,关于未知数 x 以及 y 的线性的丢番图方程(称为裴蜀等式)。

若a、b是整数, 且 gcd(a, b) = d,那么对于任意的整数 x、y, ax + by 都一定是d的倍数

特别地,一定存在整数 x、y,使ax + by = d成立。

欧几里得算法证明裴蜀定理,求得裴蜀数(x、y的一组解)

在辗转相除的回溯过程中计算x、y。

第一种情况:a、b中有一个数为0时

gcd(c, 0) = x * c + y * 0 = c, 可得:x = 1 、 y = 0

第二种情况:a与b都不为零时

a、b的递归过程为:( a, b ) -> ( b, a % b )

x、y的回溯过程为:( y, x – k * y ) <- ( x, y )

  1. 设x、y满足gcd(b, a % b) = c
  2. 所以 b * x + (a % b) * y = c ① 
  3. 等价于: b * x + (a – k * b) * y = c
  4. 合并同类项:a * y + b * (x – k * y) = c ②
  5. 所以递归回溯的下一层 gcd(a, b) = c 满足 ②
  6. 下一层的x = y, y = x – k * y (k = a / b 向下取整)

代码示例:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;

int ex_gcd(int a, int b, int &x, int &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int r = ex_gcd(b, a % b, x, y);
    int temp = y;
    y = x - a / b * y;
    x = temp;
    return r;
}

int main() {
    int a, b;
    while (cin >> a >> b) {
        int x, y;
        int c = ex_gcd(a, b, x, y);
        cout << a << " * " << x << " + " << b << " * " << y << " = " << c << endl;
    }
    return 0;
}

扩展欧几里得算法的用途

a * x % b = c, c 是a、b的最大公约数,求x的值?

  1. a * x – k * b = c
  2. a * x + b * y = c

数论中的欧拉公式

欧拉定理 aØ(n) mod n = 1:对于互质的正整数a和n,有aØ(n) mod n = 1

欧拉函数 Ø(n):对于一个正整数n,小于n且与n互质的正整数(包括1)的个数,记做Ø(n)

可推导结论:从0开始,每隔Ø(n)个数,aØ(n) mod n 等于1(循环)。

证明:

  1. aØ(n) 的值集合为:S1 = {x1,x2,x3…xØ(n)}
  2. aØ(n) 的值集合为:S2 = {a*x1,a*x2,a*x3…a*xØ(n)}
  3. x1 * x2 * x3… * xØ(n) ≡ aØ(n) * (x1 * x2 * x3… * xØ(n) ) (mod n)
  4. aØ(n) ≡ 1 (mod n)

欧拉函数 Ø(n),代码示例:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;
// 欧拉函数算法
// 在 1~n 这n个数中,2的倍数占比为1/2;
// 去掉2的倍数余下数中,3的倍数比例还是1/3;
// 再去掉3的倍数余下数中,5的倍数所占比例仍为1/5;
// 去掉的是不大于根号n的所有素数的倍数。
int phi(int n) {
    int x = 2, ans = n; // x:质因子, ans:欧拉函数的结果
    while (x * x <= n) { 
        // 将n写成其质因子幂的连乘积的形式
        // ϕ(N)=N∗(1−1/p1)∗(1−1/p2​)∗...∗(1−1/pm)
        if (n % x == 0) ans = ans / x * (x - 1); // N∗(1−1/p1) 写法转化
        while (n % x == 0) n /= x;
        x += 1;
    }
    if (n != 1) ans -= ans / n; 
    return ans;
}

int main() {
    int n;
    while (cin >> n) {
        cout << "phi(" << n << ") = " << phi(n) << endl;
    }
    return 0;
}

发表评论

邮箱地址不会被公开。