歐幾裏得與擴展
阿新 • • 發佈:2018-06-17
要求 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); 13printf("%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
歐幾裏得與擴展