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

    扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。

    扩展欧几里德常用在求解模线性方程及方程组中。

    首先,证明一下gcd(a,b)==gcd(b,a%b)

    设gcd(a,b) = k
    a = n1 * k
    b = n2 * k
    a%b = (n1%n2)*k
    b = n2 * k
    现在只需证n2 和 n1%n2 没有公因子
    假设有公因子,为r
    n2 = num2 * r
    n1%n2 = num1 * r
    n1 = k*n2 + num1*r
    n1 = (k*num2+num1)*r
    n1和n2有公因子,这与设gcd(a,b) = k矛盾,因为如果n1和n2有公因子,那么gcd(a,b)=k*r
    所以gcd(b,a%b) = gcd (a,b)

    以上证明出处

    由上面的等式,我们可得:

    ∵gcd(a,b)==gcd(b,a%b)

    ∴a*x1+b*y1==b*x2+(a%b)*y2            //一定有整数解x,y

    ∵在计算机科学里a%b的实际运算是 a-(a/b)*b        //a/b因为都是整形变量,所以计算时a/b==⌊a/b⌋

    ∴a*x1+b*y1==b*x2+(a-(a/b)*b)*y2

    整理可得a*x1+b*y1==a*y2+b*(x2-(a/b)*y2)

    x1=y2,y1=x2-(a/b)*y2

    显然,我们只要找到递归边界,就可以不断求解,直到得出答案

    辗转相除法:

    int gcd(int a,int b)
    {
    return b==0?a:gcd(b,a%b);
    }
    也就是说边界是 a*x+b*y==gcd(a,b)==a  //因为此时b==0
    那么现在x是不是就是1,y可以取任意整数
     
    以下为最简c++语言写法:

    void gcd(int a,int b,int &x,int &y)
    {
      if (b==0){x=1,y=0;return;}
      gcd(b,a%b,y,x);          //注意x,y的位置
      y-=a/b*x;
    }

     
    这里的引用解决了x1=y2,所以仅剩y1=x2-(a/b)*y2;
    又是因为引用,y1=x2,x1=y2;
    所以y1=y1-(a/b)*x1;
    不得不说,能首先写出这个的大佬,的确思维逻辑很好!!!
     
     
    当然,不用引用的话,返回一个结构体也行(貌似会更好理解)

    struct ans
    {
      int x,y;
    };
    ans gcd(int a,int b)
    {
      ans myans,t;
      if(b==0){myans.x=1,myans.y=0;return myans;}
      t=gcd(b,a%b);
      myans.x=t.y;
      myans.y=t.x-a/b*t.y;
      return myans;
    }

    可以试一下改变递归边界中的y的值,会有惊喜;

    我们得出了一组解  x,y

    显然a*x0+b*y0==a*x+b*y  //x0,y0为已得解,x,y为其他答案

    x=x0+k*b,y=y0-k*a    //k为整数,其实你将x,y带入原式,就会发现显然成立

     
  • 相关阅读:
    C#之时间统计
    Unity之屏幕画线
    Unity之坐标转换
    Unity3d之按键
    Unity3d之截图
    [Windows]A盘凭空消失
    函数的多类型传值
    isdigit()
    函数的返回值
    locals()
  • 原文地址:https://www.cnblogs.com/callmebg/p/6849672.html
Copyright © 2011-2022 走看看