美文网首页
GCD欧几里得算法 & EXGCD扩展欧几里得算法

GCD欧几里得算法 & EXGCD扩展欧几里得算法

作者: 1QzUPm_09F | 来源:发表于2017-08-06 10:42 被阅读0次

    欧几里得算法
    欧几里得算法 (Euclidean algorithm) 是用来解决最大公约数问题的,通常采用辗转相除法。


    GCD

    代码:

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

    ···············································································································
    拓展欧几里得算法
    拓展欧几里得算法(Extended Euclidean Algorithm)是基于欧几里得算法而来解一类特殊的线性丢番图方程。
    解决问题:ax+by=1(即a,b互质),求解x,y。


    扩展GCD

    代码:

    ll exgcd(ll a, ll b, ll &x, ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        ll r=exgcd(b, a%b, x, y);
        ll t=x;
        x=y;
        y=t-(a/b)*y;
        return r;
    }
    

    对于ax+by=gcd(a,b)我们可以得到一组解x和y
    但往往我们会遇到ax+by=c这样的问题,那和前面的扩展gcd又有什么关系呢?
    前提条件:若c mod gcd(a, b) =0,则该方程(ax+by=c)存在整数解,否则不存在整数解

    对于ax+by=gcd(a,b)求出来的一组整数解x0和y0
    对应ax+by=c的一组整数解x1和y1,有x1=x0(d/gcd(a,b)),y1=y0(d/gcd(a,b))
    对于全部解,有x=x0+b/gcd(a,b)t,y=y0-a/gcd(a,b)t (其中t为任意常整数)
    由于x0,y0,a,b,gcd(a,b)都是已经求出的数(可以看作常数),所以对于x,y我们可以看作是自变量为t,因变量为x,y的两个一次函数,所以可以知道,这2个函数是单调的

    x = x0 + b/gcd(a,b)*t;
    y = y0 - a/gcd(a,b)*t; 
    (x0, y0 为方程的一组特解, t为整数)
    

    证明是根据线性丢番图方程而来的。

    扩展欧几里得算法

    例题:青蛙的约会
    POJ - 1061

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long int
    
    ll gcd(ll a, ll b)
    {
        return b? gcd(b, a%b): a;
    }
    
    void exgcd(ll a, ll b, ll &x, ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return ;
        }
        exgcd(b, a%b, x, y);
        ll t=x;
        x=y;
        y=t-(a/b)*y;
        return ;
    }
    
    
    int main()
    {
        ll x, y, m, n, L;
        ll T, P, d;
        ll a, b, c;
        while(~scanf("%lld%lld%lld%lld%lld", &x, &y, &m, &n, &L))
        {
            a=n-m;
            b=L;
            c=x-y;
            d=gcd(a, b);
            if(c%d) printf("Impossible\n");
            else
            {
                int r=d;
                a/=d;
                b/=d;
                c/=d;
                exgcd(a, b, T, P);
                T=T*c;
                T=(T%b+b)%b;
                printf("%lld\n", T);
            }
        }
        return 0;
    }
    

    例题:The Balance
    POJ - 2142

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long int
    ll gcd(ll a, ll b)
    {
        return b? gcd(b, a%b): a;
    }
    
    void exgcd(ll a, ll b, ll &x, ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return ;
        }
        exgcd(b, a%b, x, y);
        ll t=x;
        x=y;
        y=t-(a/b)*y;
        return ;
    }
    
    int main()
    {
        ll a, b, c, x, y, vx, vy;
        while(~scanf("%lld%lld%lld", &a, &b, &c)&&(a||b||c))
        {
            ll r=gcd(a, b);
            a/=r;
            b/=r;
            c/=r;
            exgcd(a, b, x, y);
    
            vx=x*c;
            vx=(vx%b+b)%b;
            vy=abs((c-a*vx)/b);
    
            y=y*c;
            y=(y%a+a)%a;
            x=abs((c-b*y)/a);
    
            if(x+y>vx+vy)
            {
                x=vx;
                y=vy;
            }
    
            printf("%lld %lld\n", x, y);
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:GCD欧几里得算法 & EXGCD扩展欧几里得算法

          本文链接:https://www.haomeiwen.com/subject/nbdglxtx.html