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

    别人总结的,很详细,http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html

    欧几里得算法,就是人们常说的辗转相除法,比较好理解,主要作用是求两个数最大公约数,最小公倍数也可方便的求出

    1 int gcd(int a,int b)
    2 {
    3     return b==0?a:gcd(b,a%b);
    4 }
    View Cod

    扩展欧几里得就非常神奇了,主要作用是解不定方程, 即  a * x + b * y = c ,我们都知道可以有解,但不是唯一解

    用 exgcd 可以很快求出  a * x + b * y = gcd(a,b) 的一个特解。如果  gcd(a,b) | c   即,有整数解,否则无

    假如求出特解  x0 ,y0  那么通解 a * x + b * y = gcd(a,b)  为

    x = x0 + b / gcd(a,b) * t   ( t 为任意整数 )

    y = y0 - a / gcd(a,b) * t   ( t 同上 )

    保证了式子恒等,所以是通解,假如要求 x 的最小非负整数解即 ,设 m = b / gcd(a,b)  ,x = (x0 % m + m)%m  (前提要 b / gcd(a,b)为正)

    再回到 a * x + b * y = c 的特解,设, k = c / gcd (a,b)

    那么特解 x1 = k * x0  ,  y1 = k * x0

    式子变为 a * x1 + b * y1 = z   ,咋一看通解为  x = x1 + b * t    y = x2 - a * t

    其实不对,先将两边同除 gcd(a,b)  得  a1 * x1  + b1 * y1 =  k 

    容易看出, a * x + b * y = c 通解为

    x = x0*k + b/gcd(a,b) * t 

    y = y0*k - a/gcd(a,b) * t (t为任意整数)

    因为 b1 <= b 所以对 b1 取模一定小于等于 b,

    同样方法取最小非负解

    扩展欧几里得还可以很方便的求乘法逆元 a * x == 1 (mod m) x 即为 a 的乘法逆元

    可以变形为 a * x + m * y == 1 (mod m)

    exgcd(a,m,x,y) 后,x 可能是负数,同上方法处理 (x % m/gcd + m/gcd) % m/gcd 

     1 int exgcd(int a,int b,int &x,int &y)
     2 {
     3     if (b==0)
     4     {
     5         x=1;
     6         y=0;
     7         return a;
     8     }
     9     int r = gcd(b,a%b,y,x);
    10     y-=(a/b)*x;
    11     return r;
    12 }
    View Code
  • 相关阅读:
    POJ 3672 水题......
    POJ 3279 枚举?
    STL
    241. Different Ways to Add Parentheses
    282. Expression Add Operators
    169. Majority Element
    Weekly Contest 121
    927. Three Equal Parts
    910. Smallest Range II
    921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/7240023.html
Copyright © 2011-2022 走看看