zoukankan      html  css  js  c++  java
  • 初等数论及其应用——欧几里得算法

      欧几里得是数论当中最基本的定理,以其为基础的拓展欧几里得算法在解决同余方程、求模逆元等问题。

      首先来介绍几个概念,数论当中一些基本的概念其实在小学就学过,但是很长一段时间并没有用到它们,因此这里再拿出来温习一下。

      我们常常用a|b来表示b能够整除a(b > a),即b/a是整数,但是“|”在使用的过程中容易和绝对值、几何定义符、条件概率混淆,所以,这里我们用a来表示a能够整除b。

      约数:如果ba,则称b是a的约数。

      倍数:如果ba,则称a是b的倍数。

      最大公约数:gcd(a,b) = max{k | ka 且k}。

      最小公倍数:lcm(a,b) = min{k | k>0 , ak 且bk}

      那么现在我们面临一个重要的问题,给出一系列数字,我们想要通过一个程序得到这些数字的最大公约数或者最小公倍数, 应该怎么做呢?

      容易想到穷举,当然,容易想到的代价是牺牲大量的时间,我们需要用更好的思维去简化这个过程。

      计算最大公约数的方法:欧几里得算法.

      n>m,gcd(m,n) = gcd(n % m, m) , gcd(0,n) = n.

      证明:

      n = qm + r,r>0。
      我们假设存在这样一个d,它是m、n的公因子,即da 且 d。

      可以看到r = n - qm ,假如c = xa + yb,且da,d,那么dc。这里是同样道理,所以d ,加上之前的d,定理成立.


        

       基于这个结论,我们在求解gcd(m,n)(n > m)的时候,可以转而去求gcd(n % m , m).

      求gcd(n % m , m)的时候,可以转而去求gcd(m%(n%m) , n%m)

      ……

      这就形成了一个递归性质的求解过程,可能在说这个递归的流程你就会质疑,上面的证明过程我们给出的公因子相同,但是如何保证其是最大公因子(最大公约数)呢?想象一下这个递归过程,如果保证了递归的最后一层得到的公因子d是最大公因数,那么最终我们就会返回一个最大公约数。

    那么现在我们要解决的一个主要问题变成了:递归的最底层是什么呢?或者说,递推到什么程度开始“归”呢?想象一下,递推下去的终点,gcd(a,b)的a、b中必然有一个数是0,然后用我们在定理中定义的:gcd(a,0) = a.a其实就是整个递归过程中的解,这保证了递归过程中传递的约数一直是最大公约数。

    而在设计递归程序的时候,为了得到返回值(即上一段的a),我们规定gcd(a,b)函数a>b,这样返回结果即为:gcd(a,0),返回a.

     参考代码如下:

    #include<cstdlib>
    
    #include<iostream>
    
    using namespace std;
    
    long long gcd(int a , int b)
    
    {
    
         if(b == 0)
    
              return a;
    
         else  return gcd(b , a%b);
    
    }

      以欧几里得算法为基础进行拓展,得到的拓展欧几里得算法能够帮助我们解决更多的问题,尤其是模方程问题。

     

     

       基于上面的推导,我们就可以编程来实现这样一个求解二元一次方程ax+by=gcd(x,y)的一个特解了,参考代码如下:

     //ax + by = gcd(a,b),函数返回值为gcd(a,b)
    long long extend_gcd(long long a , long long b, long long &x , long long &y)
    {
         if(a == 0 && b == 0)  return -1;
         if(b == 0){x = 1 , y = 0;return a;}
         long long d = extend_gcd(b,a%b,y,x);
         y -= a/b*x;
         return d;
    } 

      拓展欧几里得算法一个重要应用就是求剩余系下的逆元.

                         

      与矩阵逆元类似,我们先去讨论逆元的存在性,再去解决如何求解逆元.

      

      计算方法:

      承接对逆元存在性的分析

      考察而原方程ax+my=1

      利用拓展欧几里得算法计算x(需要保证在m剩余系下)

      简单的参考代码如下:

    //ax = 1(mod n),返回x,即为a在n下的逆元
    long long mod_reverse(long long a , long long n)
    {
        long long x , y;
        long long d = extend_gcd(a,n,x,y);
        if(d == 1)  return (x%n+n)%n;
        else        return -1;
    }
  • 相关阅读:
    代数基本定义
    离散数学CONDITIONAL STATEMENTS
    欧几里德算法及其实现
    欧几里得 算法复杂度
    养成习惯
    解决在myeclipse中启动服务器就进入调试模式的方法
    oracle中对索引的操作
    schema在oracle里是什么意思(转:http://shanbei.info/schemainoraclewhatismeantin.html)
    java 加载properties 文件
    java.io.IOException: mark() not supported
  • 原文地址:https://www.cnblogs.com/rhythmic/p/5875436.html
Copyright © 2011-2022 走看看