【算法学习笔记】34:扩展欧几里得算法

裴蜀定理

描述

对于任意正整数 a a a、 b b b,一定存在整数系数 x x x, y y y,使得:
a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b)

并且 g c d ( a , b ) gcd(a, b) gcd(a,b)是对于任意的系数 x x x和 y y y放在 a a a和 b b b上能凑出的最小正整数。

证明

如下如果有整数系数 x x x、 y y y,那么 a x + b y ax + by ax+by一定是 g c d ( a , b ) gcd(a, b) gcd(a,b)的倍数,因为 a a a和 b b b都分别是 g c d ( a , b ) gcd(a, b) gcd(a,b)的倍数。因此能凑出来的数字最小就是 g c d ( a , b ) gcd(a, b) gcd(a,b)。

接下来证明一定存在 x x x、 y y y能凑出 g c d ( a , b ) gcd(a, b) gcd(a,b)。证明存在性的东西可以用构造法,只要把这个东西构造出来了,那么就一定存在了。这个构造的方法就是扩展欧几里得算法,使得对于任意的 a a a、 b b b,都能构造出来 x x x、 y y y使得 a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b)。

扩展欧几里得算法

欧几里得算法是 g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a, b) = gcd(b, a~mod~b) gcd(a,b)=gcd(b,a mod b),递归出口是当 b b b为 0 0 0时返回 a a a,因为 0 0 0和任何数的最大公约数就是那个数。

扩展欧几里得算法则是在欧几里得算法的基础上,把系数 x x x和 y y y构造出来。

考虑到欧几里得算法的递归特性,可以用之前递归出的结果计算出前面的结果。

如,欧几里得算法计算gcd的递归出口是 b b b为 0 0 0时返回 a a a,此时 a a a和 b b b的最大公约数就是 a a a,要使得 a x + b y = a ax + by = a ax+by=a,显然有一组整数解 x = 1 x = 1 x=1且 y = 0 y = 0 y=0。

考虑除了递归出口之外的递归分支,需要计算 g c d ( b , a m o d b ) gcd(b, a~mod~b) gcd(b,a mod b),假设此时已经求出一组解 y y y和 x x x(这里将 y y y和 x x x调换便于计算,不调换也是可以的,结论是另一种写法公式),即使得:
b y + ( a m o d b ) x = g c d ( b , a m o d b ) = g c d ( a , b ) by + (a~mod~b)x = gcd(b, a~mod~b) = gcd(a, b) by+(a mod b)x=gcd(b,a mod b)=gcd(a,b)

考虑到 a m o d b = a − ⌊ a b ⌋ ⋅ b a~mod~b = a - \lfloor \frac{a}{b} \rfloor \cdot b a mod b=a−⌊ba⌋⋅b,整理一下 a a a和 b b b的系数,得到:
a x + ( y − ⌊ a b ⌋ ⋅ x ) b = g c d ( a , b ) ax + (y - \lfloor \frac{a}{b} \rfloor \cdot x) b = gcd(a, b) ax+(y−⌊ba⌋⋅x)b=gcd(a,b)

因此,从上一组解的 x x x不变, y y y减去 ⌊ a b ⌋ ⋅ x \lfloor \frac{a}{b} \rfloor \cdot x ⌊ba⌋⋅x就是为 a a a和 b b b构造的系数解。

cpp 复制代码
#include <iostream>

using namespace std;

int exgcd(int a, int b, int& x, int& y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main() {
    int t; cin >> t;
    
    while (t -- ) {
        int a, b; cin >> a >> b;
        int x, y;
        exgcd(a, b, x, y);
        cout << x << ' ' << y << endl;
    }
    
    return 0;
}
相关推荐
SWAGGY..9 分钟前
【C++进阶】:(7)红黑树的原理与 C++ 实现:结构设计、插入调整及性质验证
android·java·开发语言·c++·算法
-dzk-12 分钟前
【技巧】LC 31.下一个排列
算法
(Charon)41 分钟前
【C++面试】迭代器失效是什么?vector、list、map中如何避免迭代器失效
c++·算法·面试
驭渊的小故事2 小时前
NC229023 题解:二分答案求解“最大化最小值“问题
java·算法
朝朝辞暮i2 小时前
C++ 第 36 课:Action——机械臂/VLA 非常重要
开发语言·c++·算法·ros2
ra90fy2 小时前
B3873 [GESP202309 六级] 小杨买饮料
c++·算法
Omics Pro2 小时前
北理工李荣华:AI虚拟细胞证据多模态推理基准
数据库·人工智能·算法·机器学习·自然语言处理
xieliyu.2 小时前
LeetCode 1419 数青蛙:状态模拟求最少青蛙数量|Java 题解
java·算法·leetcode
acd120092 小时前
线上偶发 499 错误,并非后端服务异常
算法
Nil2082 小时前
leetcode 45跳跃游戏Ⅱ
算法·leetcode·游戏