zoukankan      html  css  js  c++  java
  • 【数论】二进制GCD

    二进制GCD

        GCD这种通用的算法相信每个OLER都会 ,辗转相除,代码只有四行 :

    int GCD(int a,int b){
        if(b==0) return a;
        return GCD(b,a%b);
    }
    

      GCD算法使通过辗转相除法来求解两个数的最大公因数,又称欧几里得算法

         可以知道:GCD(x,y)=GCD(x,y-x)

         我们将b能被a整除记作a|b

         那么假设z是最大公因数,那么有:

                如果z|x,z|y,则z|(y-x)  (因为x和y肯定可以写作a*z=x,b*z=y,那么a*z-b*z=(a-b)*z,一定可以整除)

         那么再设z不是x的因子,则z不是x和y-x的公因子

         设z|x.z不是y的因子,则z不是x和y-x的公因子

         那么代码就是上面那个啦!

    如果想进一步提高这个算法的效率,那么我们可以选择二进制GCD

        我们可以通过不断地筛去因子2来提高算法的效率,这样的2可以是公共的或单个的,总之不影响算法的正确性

        那么为什么不是筛去因子3、因子4呢?

        因为计算机只提供2进制的快速运算(按位),所以判断a%2=?0可以直接写成!(a&1),但是其它数是没有的,我们知道计算机做取模运算的效率是很低很低的。

        那下面我们来看一看证明过程:

        GCD(x,y)=x   (x==y)

        GCD(x,y)=2*(GCD(x/2,y/2))  (!(x&1) and !(y&1))

        GCD(x,y)=GCD(x/2,y) (!(x&1) and (y&1)    因为2显然不是公因数,所以我们可以果断地筛掉它)

        GCD(x,y)=GCD(x,y/2) ((x&1) and !(y&1)    理由同上)

        GCD(x,y)=GCD(x-y,y) (辗转相减) 

        那么通过上面的推理,我们可以得出代码:

    int GCD(int x,int y){
        int i=0,j=0;
        if(x==0) return y;//if和for一定不能反,要么会炸
        if(y==0) return x;//一个没用了就返回另一个
        for(i;0==(x&1);i++) x>>=1;//化简为n*(m^2)形式
        for(j;0==(y&1);j++) y>>=1;//化简为a*(b^2)形式
        if(i>j) i=j;//去最大 公 因数,当然是你有我有的了
        while(1){
            if(x<y) x^=y,y^=x,x^=y;//二进制交换,非常高级
            if(0==(x-=y)) return y<<i;//那么就把以前的次幂乘上去,辗转减操作
            while(0==(x&1)) x>>=1;//x减了y以后可能还是成为a*(b^2)形式,要继续筛去
        }
    }
    

      

        至于LCM(最小公倍数)来说有如下定理:

        x*y=LCM(x,y)*GCD(x,y),那么只需要求出GCD以后算一下x*y/GCD(x,y)就好了

  • 相关阅读:
    高德地图在h5项目中的集成(点标记)
    angular中点击页面任意地方让显示的元素消失
    关于echars中雷达图的一些配置
    部署项目到阿里云服务器上遇到的问题
    sql语句的简单记录
    C#中的数据类型
    原型和继承
    Git 命令行使用
    以前一直设置水平居中,现在我们来讨论一下图片居中的四种小技巧
    让盒子两端对齐小技巧 => inline-block
  • 原文地址:https://www.cnblogs.com/wxjor/p/6086929.html
Copyright © 2011-2022 走看看