gcd欧几里德算法/extgcd扩展欧几里德算法以及在解不定方程中的应用

来源:互联网 发布:中科院分词 python 编辑:程序博客网 时间:2024/05/12 16:37

这个应该是我在noip前就应该会的东西 ,但是当时也许只是记下了代码吧 ,现在有诸多的不理解。后来借着书和几篇博客弄懂了并小证了一下,鉴于网上有些博客关于这个的写的真的不好看,所以自己来总结一下,顺带以后也能看。
顺带一提,gcd(a,b)表示a,b的最大公约数。

欧几里德算法

辗转相除法求最大公约数问题,同可求最小公倍数。
既然是辗转相除法,自然就是%%%,%到互相整除为止。代码也很详尽简洁。

int regulargcd(int x,int y){    return y==0?x:(regulargcd(y,x%y));}

最小公倍数为两数之积除以他们的最大公约数,相信大家都能明白。

扩展欧几里德算法

我之前一直困惑的是它为什么可以求不定方程的解,后来基本明白了:
给定一个形如方程ax+by=d,求它的整数解。
我们知道a,b为整数,d是整数,使得x,y为整数解,那么需要约掉系数中相同的部分,于是

ax+by=dgcd(a,b)|d

所以说,假设我们有d=gcd(a,b)t,则方程ax+by=d的解为agcd(a,b)x+bgcd(a.b)y=gcd(a,b)的t倍,那么原问题转化为求方程agcd(a,b)x+bgcd(a.b)y=gcd(a,b)的解了。

再推到一般,若a,b互质,有ax+by=1有解。

然后接下来我们考虑特殊解的情况:

gcd(a,b)递归的最终结果为gcd(k,0),假定方程有解,那么最终有a1+b0=gcd(a,b),即a1+b0=1,即x=1y=0出现,这是在求gcd时递归形成的。若我们也这样地求解方程呢?

于是我们来找ax+by=gcd(a,b)bx+(a%b)y=gcd(b,a%b)的关系,由于a%b=a(a/b)b(整数除法) 所以代入有

ay+b(xa/by)=gcd(a,b)=gcd(b,a%b)

于是原方程解为x=y,y=x(a/b)y
这样我们就能递归地计算方程的解了。

int extgcd(int a,int b,int &x,int &y){    if(b==0)    {        x=1;        y=0;        return a;    }    else    {        int ans;        ans=extgcd(b,a%b,x,y);        int tmp=x;        x=y;        y=tmp-(a/b)*y;        return ans;    }}

不定方程不是有很多解吗?是的,这只是最小解。设最小解为x0,y0,它的所有解为x=x0+bgcd(a,b)y=y0+agcd(a,b)。(自己带到方程里展开就有恒等式,这里不证了)当gcd(a,b)=1时,有x=x0+b,y=y0+a

    while(x<=0)    {        x+=(b/res);    }    printf("%d\n",x);

例题:zoj3609求逆元
方法同上,AC代码

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <vector>#include <queue>//zoj3609 ACusing namespace std;int extgcd(int a,int b,int &x,int &y){    if(b==0)    {        x=1;        y=0;        return a;    }    else    {        int ans;        ans=extgcd(b,a%b,x,y);        int tmp=x;        x=y;        y=tmp-(a/b)*y;        return ans;    }}int regulargcd(int x,int y){    return y==0?x:(regulargcd(y,x%y));}int main(){    int a,b;    int cas;    scanf("%d",&cas);    for(int z=0;z<cas;z++)    {        scanf("%d%d",&a,&b);        int x,y;        if(regulargcd(a,b)==1)        {            int res=extgcd(a,b,x,y);            if(x>0)            {                printf("%d\n",x);            }            else            {                while(x<=0)                {                    x+=(b/res);                }                printf("%d\n",x);            }        }        else        {            printf("Not Exist\n");        }    }    return 0;}

关于逆元,请移步逆元-wiki
谢谢看到这里

0 0
原创粉丝点击