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

歐幾裏得與擴展

要求 mic 比較 wap log mod https ace printf

歐幾裏得:

gcd遞歸定義:對於任意正整數b,gcd(a,b)= gcd(b,a mod b)。

證明:

  

  只需要證明上面兩者能相互整除。

  設gcd(a,b)= d,所以d | a 且 d | b。由帶余除法可以得出:

  a mod b = a - qb。其中 q = └a / b┘.所以 a mod b 是a 和 b的一個線性方程組合,
  
  所以d |a mod b。又因為 d | b,所以 d | gcd(b,a mod b),即gcd(a,b)|gcd(b,a mod b)。
  
  證明gcd(b,a mod b)|gcd(a,b)和上述過程幾乎一樣。

  

代碼實現:

  

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 int a,b;
 5 int gcd(int a,int b)
 6 {
 7     if(a<b)swap(a,b);        //此處註意,why?仔細想想。 
 8     return a%b==0?b:gcd(b,a%b);
 9 }
10 int main()
11 {
12     scanf("%d%d",&a,&b);
13
printf("%d",gcd(a,b)); 14 }

gcd 比較簡單,接下來才是重頭戲 --- 擴展。

擴展歐幾裏得:

  這東西看似沒啥用,實際其應用範圍很廣(逆元,不定方程...)。

  現在我們有這樣一個問題:

    求解不定方程 ax + by = gcd(a,b).(假設 a >= b ).

 

當 b=0 時有 gcd(a,b)=a,此時 x=1,y=0
當 b 不為 0 時,根據 GCD 遞歸定理 gcd(a,b)=gcd(b, a mod b)
可得 ax+ by=gcd(a, b)=gcd(b, a mod b)=bx′ +(a mod b)y′

即 ax+by=bx′+(a mod b)y′ = bx′+(a−b)×⌊a/b⌋y′
移項得 ax+by=bx′+(a mod b)y=ay‘+b(x-⌊a/b⌋y)

所以x=y‘,y=x‘-
⌊ a/b ⌋y‘.

  設(xo,yo)是不定方程 ax+by=m 的一組解,(a,b)=g,那麽全部解為

    (xo+(b/g)t , yo - (a/g)t),其中 t 為所有整數.

  

模板代碼:

 1 #include <cstdio>
 2 int exgcd(int a, int b, int &x, int &y)        //非遞歸版 
 3 {
 4     int d;
 5     if (!b) x = 1, y = 0, d = a;
 6     else
 7     {
 8         d = exgcd(b, a % b, y, x);
 9         y -= (a / b) * x;
10     }
11     return d;
12 }
13 int exgcd(int a, int b, int &x, int &y)        //遞歸版 
14 {
15     int d;
16     return !b ? (x = 1, y = 0, a) : (d = exgcd(b, a % b, y, x), y -= (a / b) * x, d);
17 }
18 int main()
19 {
20     int a, b, x, y;
21     scanf ("%d%d", &a, &b);
22     printf("%d\n", exgcd(a, b, x, y));
23     printf("%d %d\n", x, y);
24 }

習題練習:

  NOIP 2012 同余方程

  求關於 x 的同余方程ax ≡ 1(mod b) 即求解 ax + by = 1 中的 x 值,註意題目要求 正整數。

  不是模板,勝似模板。

  代碼:

 1 #include <cstdio>
 2 int exgcd(int a, int b, int &x, int &y) {
 3     int d;
 4     return !b ? (x = 1, y = 0, a) : (d = exgcd(b, a % b, y, x), y -= (a / b) * x, d);
 5 }
 6 int main()
 7 {
 8     int a, b, x, y;
 9     scanf ("%d%d", &a, &b);
10     exgcd(a, b, x, y);
11     int k=(0-x) /b;
12     x=x+k*b;
13     while(x<0){ x+=b; }     //處理負數 
14     printf("%d", x);
15 }

作者:RMY

出處:https://www.cnblogs.com/rmy020718/p/9192002.html

歐幾裏得與擴展