zoukankan      html  css  js  c++  java
  • AcWing 877. 扩展欧几里得算法

    题目传送门

    一、理解和感悟

    1、裴蜀定理

    裴蜀定理(或贝祖定理)得名于法国数学家艾蒂安·裴蜀,说明了对任何整数(a)(b)和它们的最大公约数(d),关于未知数(x)(y)的线性不定方程(称为裴蜀等式):若(a),(b)是整数,且(gcd(a,b)=d),那么对于任意的整数(x),(y),(ax+by)都一定是(d)的倍数,特别地,一定存在整数(x),(y),使(ax+by=d)成立

    推论:(a),(b)互质的充分必要条件是存在整数(x),(y)使(ax+by=1)

    举个栗子:
    (2x+y=3)

    那么(a=2),(b=1),(m=3),(gcd(2,1)=1),(3)(1)的倍数,所以这个方程一定要整数解。
    比如(x=1),(y=1)就是一个整数解,还可以有(x=-2),(y=7)也是一组整数解。

    注意:如果一个二元一次方程有正整数解,那么不只是一组解。

    再举一个栗子:
    (4x+2y=5)
    有没有整数解呢?没有,因为(a=4,b=2,m=5,gcd(4,2)=2,5)是除不开(2)的,所以没有整数解!

    2、如何求贝祖数?

    什么是贝祖数?
    比如:(2x+y=3),那么符合这个等式的(x=1),(y=1)就是一组贝祖数。

    在计算机算法中,可以使用扩展欧几里得算法求贝祖数

    举个栗子:
    (104x+40y=8) ,有没有合适的(x,y),也就是求贝祖数。

    通过贝祖定理看一下,它是不是有解: (gcd(104,40)=8),(8)(8)的倍数,所以此方程一定有解,那么解是什么呢?

    QQ截图20210301141004.png

    扩展欧几里得算法的推导过程:

    我们先来求方程 (ax+by=gcd(a,b))的解

    ((1))、当 (b=0)

    (ax+by=gcd(a,0)),也就是:(ax=gcd(a,0)=a),所以(x=1)

    那么(y)呢?因为普遍意义上的求贝祖数,一般是指不小于零的一组解,那么不小于(0)的第一个可能(y)值就是:(y=0),所以,可以将(x=1,y=0)做为一组特解返回,也就是返回了一组“不小于零的贝祖数”。

    ((2))、当 (b≠0)

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

    并且(① ax+by=gcd(a,b))

    ( herefore bx′+(a\%b)y′=gcd(a,b))

    (ecause a−⌊a/b⌋∗b=a\%b)

    ( herefore bx′+(a−⌊a/b⌋∗b)y′=gcd(a,b))

    变形一下:

    (② ay′+b(x′−⌊a/b⌋∗y′)=gcd(a,b))

    对比(① ②)系数:

    ( herefore) (x=y′,y=x′−⌊a/b⌋∗y′)

    因此可以采取递归算法 先求出下一层的(x′)(y′) 再利用上述公式回代即可

    二、完整代码

    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    /**
     * 功能:扩展欧几里得算法模板
     * @param a 第一个数
     * @param b 第二个数
     * @param x 贝祖数x 最小非负整数
     * @param y 贝祖数y 最小非负整数
     * @return
     */
    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() {
        //优化输入
        ios::sync_with_stdio(false);
        int n;
        cin >> n;
        while (n--) {
            int a, b;
            cin >> a >> b;
            int x, y;
            exgcd(a, b, x, y);
            printf("%d %d
    ", x, y);
        }
        return 0;
    }
    
  • 相关阅读:
    exe4j的使用
    java线程生命周期及其对应方法
    自动登录开心网
    java小知识点
    java工具类目录
    java 上传图片
    eclipse+svn
    maven
    读propert文件
    hadoop学习
  • 原文地址:https://www.cnblogs.com/littlehb/p/15375125.html
Copyright © 2011-2022 走看看