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

    扩展欧几里得算法

    为了介绍扩展欧几里得,我们先介绍一下贝祖定理

               即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。

    换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍。(可以来判断一个这样的式子有没有解)

    有一个直接的应用就是 如果ax+by=1有解,那么gcd(a,b)=1;

    要求出这个最大公因数gcd(a,b),我们最容易想到的就是古老悠久而又相当强大的辗转相除法:

    int gcd(int a,int b)
    {
    return b==0?a:gcd(b,a%b);
    }


    但是,对于上面的式子ax+by=m来说,我们并不仅仅想要知道有没有解,而是想要知道在有解的情况下这个解到底是多少。

    所以,扩展欧几里得

            当到达递归边界的时候,b==0,a=gcd(a,b) 这时可以观察出来这个式子的一个解:a*1+b*0=gcd(a,b),x=1,y=0,注意这时的a和b已经不是最开始的那个a和b了,所以我们如果想要求出解x和y,就要回到最开始的模样。(倒着递归回去)

            初步想法:由于是递归的算法,如果我们知道了这一层和上一层的关系,一层一层推下去,就可以推到最开始的。类似数学上的数学归纳法。

            假设当前我们在求的时a和b的最大公约数,而我们已经求出了下一个状态:b和a%b的最大公因数,并且求出了一组x1和y1使得                          b*x1+(a%b)*y1=gcd

    (注意在递归算法中,永远都是先得到下面一个状态的值)

    这时我们可以试着去寻找这两个相邻状态的关系:

    首先我们知道:a%b=a-(a/b)*b;带入:

    b*x1 + (a-(a/b)*b)*y1

    = b*x1 + a*y1 – (a/b)*b*y1

    = a*y1 + b*(x1 – a/b*y1) = gcd   发现 x = y1 , y = y1 – a/b*x

    这样我们就得到了每两个相邻状态的x和y的转化,就可以在求gcd的同时对x和y进行求值了

    代码

    #include<iostream>
    #include<cmath>
    using namespace std;
    int exgcd(int a, int b, int &x, int &y)
    {
        if (b == 0)
        {
            x = 1; y = 0;
            return a;
        }
        int r=exgcd(a, a%b, x, y);
        int temp = y;
        x = y;
        y = x - (a / b)*temp;
        return r;
    
    }

    算法应用

    求解逆元

    逆元的概念:对于缩系中的元素,每个数a均有唯一的与之对应的乘法逆元x,使得ax≡1(mod n)。一个数有逆元的充分必要条件是gcd(a,n)=1,此逆元唯一存在。

    逆元的意义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x

    给定模数n,求a的逆相当于求解ax=1(mod n),这个方程可以转化为ax-my=1,然后套用二元一次方程的方法,用扩展欧几里得算法求得一组x0,y0和gcd;

    检查gcd是否为1,gcd不为1说明逆元不存在,若为1,调整x0到0~m-1的范围中即可。

    代码

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    long long x, y;
    long long exgcd(long long a, long long b, long long &x, long long &y)
    {
        if (b == 0)
        {
            x = 1; y = 0;
            return a;
        }
        long long r = exgcd(b, a%b, y, x);//因为x变为y,所以xy互换位置
        y -= (a / b)*x;
        return r;
    }
    long long reverse(long long a, long long n)//ax=1(mod n) 求a的逆元x 
    {    
        long long d;
        d = exgcd(a, n, x, y);
        if (d == 1)//若为1,调整x0到0~m-1的范围中即可
            return (x%n + n) % n;
        else return -1;//gcd不为1说明逆元不存在
    }

    原文链接:https://blog.csdn.net/destiny1507/article/details/81750874、https://blog.csdn.net/Greenary/article/details/79343176

  • 相关阅读:
    不务正业系列-浅谈《过气堡垒》,一个RTS玩家的视角
    [LeetCode] 54. Spiral Matrix
    [LeetCode] 40. Combination Sum II
    138. Copy List with Random Pointer
    310. Minimum Height Trees
    4. Median of Two Sorted Arrays
    153. Find Minimum in Rotated Sorted Array
    33. Search in Rotated Sorted Array
    35. Search Insert Position
    278. First Bad Version
  • 原文地址:https://www.cnblogs.com/Jason66661010/p/12939709.html
Copyright © 2011-2022 走看看