【学习笔记】求最大公约数算法及扩展欧几里得算法介绍

求最大公约数算法介绍

1.更相减损术

算法原理:欲求\(a\)\(b\)的最大公约数,设\(gcd(a,b)\)\(m\),故\(a\)\(m\)的倍数,\(b\)\(m\)的倍数,则\(a-b\)自然也是\(m\)的倍数,故有$$gcd(a,b)=gcd(b,a-b)(假定a>b)$$
\(b\)变为0,则\(a\)便是我们所需求解的最大公约数。

代码如下:

ll minus_gcd(ll x,ll y){
    while(x!=y){
        if(x<y) swap(x,y);
        x-=y;
    }
    return x;
}

时间复杂度分析:避免了效率较低的取模运算,但算法不稳定,最坏时间复杂度为\(O(max(a,b))\)。举例:\(a\)为10000,\(b\)为1,则需迭代9999次。

注:最好不要递归写,更相减损术的递归次数可能很大,导致爆栈

2.辗转相除法

算法原理:总体思路与更相减损术类似,但使用取模避免了多次相减。

代码如下:

ll mod_gcd(ll x,ll y){
    return y==0?x:mod_gcd(y,x%y);
}

时间复杂度分析:总体上时间复杂度为\(O(log(max(a,b)))\),但因取模效率较低,在实际数据中有所波动,对于大数据尤其是高精度较不方便。

3.更相减损术与位运算结合

算法原理:欲求\(gcd(a,b)\),可分情况讨论:
1.若\(a\)\(b\)均是偶数,则$$gcd(a,b)=2*gcd(a/2,b/2)=gcd(a>>1,b>>1)<<1$$
2.若\(a\)是奇数,\(b\)是偶数,则$$gcd(a,b)=gcd(a,b>>1)$$
3.若\(a\)是偶数,\(b\)是奇数,则与2类似。
4.若\(a\)\(b\)均是奇数,则$$gcd(a,b)=gcd(b,a-b)(假定a>b)$$\(a-b\)必定是偶数,可使用移位运算。
递归结束条件:\(b=0\)
代码如下:

ll bit_gcd(ll x,ll y){
    if(y==x) {
        return x;
    }
    if(x<y) swap(x,y);
    if(!x&1&&!y&&1) return bit_gcd(x>>1,y>>1)<<1;
    else if(x&1&&!y&1) return bit_gcd(x,y>>1);
    else if(!x&1&&y&1) return bit_gcd(x>>1,y);
    else return bit_gcd(y,x-y);
}

时间复杂度分析:总体时间复杂度为\(O(log(max(a,b)))\),比较优秀。

扩展欧几里得定理介绍

问题引入:给定整数a、b、c,求一组整数解x、y使\(ax+by=c\)成立

引理:若上述方程有解,则\(gcd(a,b)|c\)成立。
证明:使上述方程两边同除以\(gcd(a,b)\),左侧仍为整数,故右侧也应为整数,故\(gcd(a,b)|c\)

所以问题转化为\(ax'+by'=gcd(a,b)\),设\(x\)\(y\)为原方程的解,则有$$x=x'(c/gcd(a,b)),y=y'(c/gcd(a,b))$$
故最后求得x'与y'之后应及时求出x与y。

由辗转相除法知,

\[ax'+by'=gcd(a,b)=gcd(b,a\;mod\;b)=bx''+(a\;mod\;b)*y'' \]

在计算机中,\(a\;mod\;b=a-b*(a/b)\),因此上式也可以转化为

\[ax'+by'=bx''+(a-b*(a/b))y''=ay''+b(x''-(a/b)*y'') \]

因此,有下列等式关系:\(x'=y''、y'=x''-(a/b)*y''\)
采用递归,当b=0时回溯,逐层求出x与y的值,最后得到最初的\(x'\)\(y'\),并进一步得到\(x\)\(y\)

代码如下:

inline void ex_gcd(ll a,ll b,ll x,ll y){
    if(b==0) {
        x=1;y=0;
        return;
    }
    ex_gcd(b,a%b,x,y);
    ll tmp=x;
    x=y;y=tmp-a/b*y;
}

注:上面的代码仅是得到了\(x'\)\(y'\)

posted @ 2021-10-30 20:35  蔚蓝-星辰  阅读(506)  评论(0)    收藏  举报