1. 程式人生 > >歐幾裏得和擴展歐幾裏得

歐幾裏得和擴展歐幾裏得

close 兩個 .com 理解 分享 ont pre spl 不定方程

別人總結的,很詳細,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

歐幾裏得和擴展歐幾裏得