zoukankan      html  css  js  c++  java
  • 欧几里得算法及其扩展

      先来看看欧几里得算法:

     1 public class Gcd {
     2     /**
     3      * 欧几里德算法,即辗转相除法 最大公约数
     4      */
     5     public static long gcd(long m, long n) {
     6         return n == 0 ? m : gcd(n, m % n);
     7     }
     8 
     9     /**
    10      * 最小公倍数lowest common multiple (LCM)
    11      * 最小公倍数 = a * b / a和b的最大公约数
    12      */
    13     private static long lcm(long a, long b) {
    14         return a * b / gcd(a, b);
    15     }
    16 }

      接着再来看裴蜀(贝祖)等式:对于任何整数a、b和它们的最大公约数d,关于未知数x和y的线性丢番图方程(称为裴蜀等式):ax+by = m 有整数解时当且仅当m是d的倍数。x、y可用扩展欧几里得算法求得。特别地,方程ax+by=1 有整数解当且仅当整数a和b互质。

      那什么是扩展欧几里得算法呢?

      现在我们知道了 a 和 b 的最大公约数是 gcd(a,b) 后面用gcd表示 ,那么,我们一定能够找到这样的 x 和 y ,使得: a*x + b*y = gcd 。这是一个不定方程。那么,怎么求出这个特解 x 和 y 呢?只需要在欧几里德算法的基础上加点改动就行了。我们观察到:欧几里德算法停止的状态是: a= gcd , b = 0 ,那么,这是否能给我们求解 x y 提供一种思路呢?

      首先,将a=gcd,b=0代入原方程,得到gcd*x+0*y=gcd。那么,这时候,只要x = 1 ,y 是 0 或者其他值(无所谓是多少,反正任何数乘以 0 都等于 0, 但是 x 一定要是 1),这时,我们就会有: a*1 + b*0 = gcd。 当然这是最终状态,但是我们是否可以从最终状态反推到最初的状态呢?

      假设当前我们要处理的是求出 a 和 b的最大公约数,并求出 x 和 y 使得 a*x + b*y= gcd ,而我们已经求出了下一个状态:b 和 a%b 的最大公约数,并且求出了一组x1 和y1 使得: b*x1 + (a%b)*y1 = gcd , 那么这两个相邻的状态之间是否存在一种关系呢?

      首先a可以表示成 a = b*t + k,而 t = a/b(这里的 “/” 指的是整除),k = a%b ,所以 可以得到a = b*(a/b) +k  -->  k=a-(a/b)*b  -->  a%b = a - (a/b)*b,代入 b*x1 + (a%b)*y1 = gcd。

      那么,我们可以进一步得到:gcd = b*x1 + (a-(a/b)*b)*y1
                       = b*x1 + a*y1 – (a/b)*b*y1
                       = a*y1 + b*(x1 – a/b*y1)

         对比之前我们的状态:求一组 x 和 y 使得:a*x + b*y = gcd ,是否发现了什么?

         这里: x = y1

               y = x1 – a/b*y1

      现在我们找到一组特殊的解  x0 和 y0,那么,我们就可以用 x0 和 y0 表示出整个不定方程的通解:

         x = x0 + (b/gcd)*t  ( t 取任意整数)

              y = y0 – (a/gcd)*t

      如果我们想要得到 x 大于 0 的第一个解的话,那么表达式就是:

        b /= d

        x = ( x0%b + b) % b

         以上就是扩展欧几里德算法的全部过程,依然用递归写:

     1 public class ExtGcd {
     2     static long x;
     3     static long y;
     4 
     5     public static long gcd(long m, long n) {
     6         return n == 0 ? m : gcd(n, m % n);
     7     }
     8     /**
     9      * 扩展欧几里得
    10      * 调用完成后 静态变量xy是ax+by=m的解
    11      * 返回的还是最大公约数
    12      */
    13     public static long ext_gcd(long a,long b){
    14         if (b==0) { // 求出了最大公约数 为a
    15             x = 1;
    16             y = 0;
    17             return a;
    18         }
    19         long res = ext_gcd(b, a % b);
    20         //x,y已经被下一层递归更新了
    21         long x1 = x;//备份x
    22         x = y;//更新x
    23         y = x1 - a / b * y;//更新y
    24         return res;
    25     }
    26     public static void main(String[] args) {
    27         System.out.println(ext_gcd(2, 7));  // 1
    28         System.out.println(x+" "+y);        // -3 1
    29     }
    30 }

      最后再来看一下这个线性方程(或者叫二元一次不定方程):ax+by = m 。有整数解时当且仅当m是gcd的倍数

      public static long linearEquation(long a, long b, long m) throws Exception {
        long d = ext_gcd(a, b);
        //m不是gcd(a,b)的倍数,这个方程无解
        if (m % d != 0) {
          throw new Exception("无解");
        }
        long n = m / d;//约一下,考虑m是d的倍数
        x *= n;
        y *= n;
        return d;
      }

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

       (1)求解不定方程;

       (2)求解模线性方程(线性同余方程)与逆元;

  • 相关阅读:
    奇数阶魔方问题
    《DSP using MATLAB》示例9.3
    《DSP using MATLAB》示例9.2
    《DSP using MATLAB》示例9.1
    找个目标很重要
    《DSP using MATLAB》示例Example 8.30
    《DSP using MATLAB》示例Example 8.29
    《DSP using MATLAB》示例Example 8.28
    《DSP using MATLAB》示例Example 8.27
    《DSP using MATLAB》示例Example 8.26
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10331666.html
Copyright © 2011-2022 走看看