zoukankan      html  css  js  c++  java
  • 扩展欧几里德算法的应用

    感谢:http://blog.csdn.net/u014634338/article/details/40210435

    扩展欧几里德算法的应用主要有以下三方面:

    (1)求解不定方程;

    (2)求解模的逆元;

    (3)求解模线性方程(线性同余方程);

    一、解不定方程

     

       对于不定整数方程pa+qb=c,

     1.若 c mod gcd(p, q)=0,则该方程存在整数解,否则不存在整数解。
       2.在找到p * a+q * b = gcd(p, q)的一组解p0,q0后,p * a+q * b = gcd(p, q)的其他整数解满足:
        p = p0 + b/gcd(p, q) * t 
        q = q0 - a/gcd(p, q) * t(其中t为任意整数)

      由此可以求出p * a+q * b = gcd(p, q)的一系列解


       3.至于pa+qb=c的整数解,只需将p * a+q * b = gcd(p, q)的每个解乘上 c/Gcd(p, q) 即可。

       在找到p * a+q * b = gcd(a, b)的一组解p0,q0后,应该是得到p * a+q * b = c的一组解

       p1 = p0*(c/Gcd(a,b)),q1 = q0*(c/Gcd(a,b))

       p * a+q * b = c的其他整数解满足:

        p = p1 + b/gcd(a, b) * t
        q = q1 - a/gcd(a, b) * t(其中t为任意整数)
        p 、q就是p * a+q * b = c的所有整数解。

      

    #include <iostream>
    #include <stdio.h>
    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(b, a%b, x, y);
        int t=y;
        y=x-(a/b)*y;    
        x=t;
        return r;
    }
    int main()
    {
        int x,y,a=5,b=6,n=3;
        int ans=exgcd(a,b, x, y);
        if(n%ans){///无整数解
            printf("NO
    ");
        }
        else
        {
            cout<<a<<"x+"<<b<<"y="<<ans<<"的一个整数解为:"<<endl;
            cout<<"x="<<x<<" "<<"y="<<y<<" "<<endl;
            cout<<"a*x+b*y=gcd(a,b)前10个解
    ";
            int p=x+b/ans;///1.
            int q=y-a/ans;
            int o=1;
            while(1){
                if(o==10)break;
                cout<<"x="<<p<<" "<<"y="<<q<<" "<<endl;
                o++;
                p=x+b/ans*o;
                q=y-a/ans*o;
            }
            cout<<"a*x+b*y=n*gcd(a,b)前10个解
    ";
            p = p*(n/ans);///2.
            q = q*(n/ans);
            o=1;
            while(1){
                if(o==10)break;
                cout<<"x="<<p<<" "<<"y="<<q<<" "<<endl;
                o++;
                p=x+b/ans*o;
                q=y-a/ans*o;
            }
    
            ///求最小整数解
            int t=x*n/ans;///3.
            int temp=b/ans;
            t=(t%temp+temp)%temp;
            int s=(n-a*t)/b;
            cout<<a<<"x+"<<b<<"y="<<n<<"的Xmin整数解为:"<<endl;
            cout<<"x="<<t<<" "<<"y="<<s<<" "<<endl;
        }
        return 0;
    }

    二、求乘法逆元

    如果a×b≡1 mod n,则a、b互为乘法逆元(也就是(a*b)%n=1)。

    扩展欧几里德算法不仅可以用来求两个正整数的最大公约数,如果这两个正整数互素,还能确定他们的逆元。
    定义:如果整数b≥1,gcd(a , b)=1,那么a有一个模b的乘法逆元a-1,使得
    a×a-1 ≡1mod b
    在这里a-1叫做a模b的乘法逆元。
    定理:若任给整数a>0, b>0, 则存在两个整数m, n使得
    gcd(a, b) = ma + nb
    若a与b互素,则ma + nb=1 (注:m,n具有相反的正负号) ,即
    am ≡1 mod b
    因此a模b的乘法逆元为m,若求出这个m,则求到了a模b的乘法逆元

    若a与b不互素,则a模b没有乘法逆元!

    一般,我们能够找到无数组解满足条件,但是一般是让你求解出最小的那组解,怎么做?我们求解出来了一个特殊的解 x0 那么,我们用 x0 % m其实就得到了最小的解了。为什么?

    可以这样思考:

        x 的通解不是 x0 + n*t(n>=0的整数) 吗?

        那么,也就是说, a 关于 m 的逆元是一个关于 m 同余的,那么根据最小整数原理,一定存在一个最小的正整数,它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,这就好解释了。

        可能有人注意到了,这里,我写通解的时候并不是 x0 + (m/gcd)*t ,但是想想一下就明白了,gcd = 1,所以写了跟没写是一样的,但是,由于问题的特殊性,有时候我们得到的特解 x0 是一个负数,还有的时候我们的 m 也是一个负数这怎么办?

        当 m 是负数的时候,我们取 m 的绝对值就行了,当 x0 是负数的时候,他模上 m 的结果仍然是负数(在计算机计算的结果上是这样的,虽然定义的时候不是这样的),这时候,我们仍然让 x0 对abs(m) 取模,然后结果再加上abs(m) 就行了,于是,我们不难写出下面的代码求解一个数 a 对于另一个数 m 的乘法逆元:

    int cal(int a,int n)
    {
        int x,y;
        int gcd(ex_gcd(a, n, x, y));
        if(1%gcd!=0)
        {
            return -1;
        }
        x*=1/gcd;
        n=abs(n);
        int ans=x%n;
        if(ans<=0)
            ans+=n;
        return ans;
    }
  • 相关阅读:
    mysql中cast() 和convert()的用法讲解
    li内有span需要右浮的问题
    svn检出项目
    vue中的 ref 和 $refs
    for in 循环 和for循环 for of循环
    setInterval()、clearInterval()、setTimeout()和clearTimeout() js计数器方法(还有第三个参数)
    利用history.pushState()实现页面无刷新更新
    函数isNaN() parseFloat() parseInt() Math对象
    一个关于margin-top的问题
    vue 父子组件之间传参
  • 原文地址:https://www.cnblogs.com/kimsimple/p/6681200.html
Copyright © 2011-2022 走看看