📅  最后修改于: 2023-12-03 14:56:00.473000             🧑  作者: Mango
线性同余方程(Linear Congruence Equation)是一个形如 Ax ≡ B(mod N) 的数学问题,其中 A、B、N 是已知的整数,求同余方程的解 x,使得 0 ≤ x < N。
我们现在要研究 x 在什么情况下有解以及怎么求解。
现在我们找到了一些能够凑出 B 的数(就是同余的意思),假设是 ai(ai 满足 A * ai ≡ B (mod N)),这个方程最终的解将会是如下形式:
x = a1 + k * N,其中 k 是整数
通式可以理解为所有可能解的集合是 a1 + N 的倍数。
我们需要找到所有ai,需要遍历这N个数列。如果所有数列都没有满足 A * ai ≡ B (mod N),返回无解。
如果只有一个解,怎么求?
直接使用扩展欧几里得算法,求解 ax + by = gcd(a, n) 的整数解。
如果已知多个解,怎么选?
如果我们求出来了一些解,最优解应该是使得 a1 为正且最小的那个值。如果有负的解也需要对 N 取模,逐一判断。
def gcd(a, b):
return a if b == 0 else gcd(b, a % b)
def extend_gcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, g = extend_gcd(b, a % b)
return y, x - a // b * y, g
def linear_congruence(a, b, n):
g = gcd(a, n)
if b % g != 0:
return []
a, b, n = a // g, b // g, n // g
x, y, g = extend_gcd(a, n)
if g != 1:
return []
return [(x * (b % n) % n + n) % n + i * n for i in range(g)]
print(linear_congruence(3, 2, 7)) # [5]
print(linear_congruence(6, 4, 20)) # [2, 7, 12, 17]
#include <iostream>
#include <vector>
using namespace std;
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b); // Euclidean Algorithm
}
int extend_gcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1, y = 0;
return a;
} else {
int g = extend_gcd(b, a % b, y, x);
y -= a / b * x;
return g;
}
}
vector<int> linear_congruence(int a, int b, int n) {
vector<int> res;
int x, y, g;
g = gcd(a, n);
if (b % g != 0) {
return res;
}
a /= g, b /= g, n /= g;
extend_gcd(a, n, x, y);
for (int i = 0; i < g; i++) {
res.push_back((x * (b % n) % n + n) % n + i * n);
}
return res;
}
int main() {
vector<int> res = linear_congruence(3, 2, 7);
for (int i = 0; i < res.size(); i++) {
cout << res[i] << " ";
}
cout << endl;
res = linear_congruence(6, 4, 20);
for (int i = 0; i < res.size(); i++) {
cout << res[i] << " ";
}
cout << endl;
return 0;
}
以上代码实现只适用于解有限解的线性同余方程。对于解集很大、无限的情况,我们还可以使用 Baby-Step Giant-Step、Pollard Rho 等算法进行优化。