扩展欧几里得算法 & 线性同余方程

 

正文

扩展欧几里得算法

c++

扩展欧几里得算法

/*
* 扩展欧几里得算法
*
* ai×xi+bi×yi=gcd(ai,bi)
*
* 之前欧几里得算法已经有过证明,这里简述是如何扩展 gcd 求得方程解的
*
* 递归终点,b = 0 时, gcd(a, b) = a
* a * 1 + b * 0 = gcd(a, b)
* 也就是说在递归终点,我们可以得到 gcd(a, b) 的一组解,那么这一组解能否往上推呢?
* 当并非递归终点,b != 0时候,假设
* ret = extend_gcd(b, a % b, x, y)
* 假设该方程 b * x + (a % b) * y = gcd(a, a % b)
*
* 因为 gcd(a, b) == gcd(b, a % b),并且 a % b = a - (a // b) * b,
*
* 带入可得
* b * x + (a - (a // b) * b) * y = gcd(a, b)
* 整理可得
* a * y + b * (x - (a // b) * y) = gcd(a, b)
* 得到 a, b 的一组解
* (y, x - (a // b) * y)
*
* 因此是可以递归求解的,我们可以从递归终点,一点点向上推导。
*
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
typedef long long LL;
int n;
LL extend_gcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) {
x = 1, y = 0;
return a;
} else {
LL ret = extend_gcd(b, a % b, y, x);
y -= x * (a / b);
return ret;
}
}
int main()
{
LL a, b, x, y, greatest_common_divisor;
scanf("%d", &n);
while (n -- ) {
scanf("%lld%lld", &a, &b);
greatest_common_divisor = extend_gcd(a, b, x, y);
printf("%lld %lld\n", x, y);
}
return 0;
}

线性同余方程

c++

线性同余方程

/*
* 扩展欧几里得算法 求解 线性同余方程
* 线性同余方程组
* ax % m = b % m
* 做一些等式的转化
* ax + my = b
* 这就是欧几里得求解线性同于方程的做法了
*
* 而且 b 一定是 gcd(a, m) 的倍数,否则就不存在解。
*
* ai×xi+bi×yi=gcd(ai,bi)
*
* 不过这里需要注意数据范围
* a * x + b * y = gcd(a, b)
* a * b - b * a = 0
* -->
* a * (x + b) + b * (y - a) = gcd(a, b)
* --> 因为 a, b是大于等于 0 的,因此 我们让 x, y 保持在 0附近最好,
*
* // x * (b / greatest_common_divisor) 请注意这个结果可以再次对 m 求余数,直接挪到 y 那里去
*
* 关键是最后这几个 简化的步骤,有点意思
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
typedef long long LL;
int n;
LL t1, t2, t;
LL extend_gcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) {
x = 1, y = 0;
return a;
} else {
LL ret = extend_gcd(b, a % b, y, x);
y -= x * (a / b);
t = x / b;
x = x - t * b;
y = y + t * a;
// printf("%lld * %lld + %lld * %lld = %lld, -->%lld\n", a, x, b, y, ret, a * x + b * y);
return ret;
}
}
int main()
{
LL a, b, x, y, m, greatest_common_divisor;
scanf("%d", &n);
while (n -- ) {
scanf("%lld%lld%lld", &a, &b, &m);
greatest_common_divisor = extend_gcd(a, m, x, y);
// printf("a=%lld, m=%lld, gcd(a, m)=(%lld), b=%lld, x=%lld, y=%lld\n", a, m , greatest_common_divisor, b, x, y);
if (b % greatest_common_divisor == 0) {
// x * (b / greatest_common_divisor) 请注意这个结果可以再次对 m 求余数,直接挪到 y 那里去
printf("%lld\n", x * (b / greatest_common_divisor) % m);
} else {
printf("impossible\n");
}
}
return 0;
}
posted @   lucky_light  阅读(75)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示