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)求解模线性方程(线性同余方程)与逆元;

  • 相关阅读:
    Windows下如何检测用户修改了系统时间并且把系统时间改回来
    洛谷 1220 关路灯
    洛谷 2279 [HNOI2003]消防局的设立
    洛谷 1498 南蛮图腾
    bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板
    codevs 1021 玛丽卡 SPFA
    codevs 1077 多源最短路 flyod
    Vijos P1133 装箱问题 01背包
    codevs 1069 关押罪犯 并查集
    codevs 1073 家族 并查集
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10331666.html
Copyright © 2011-2022 走看看