欧几里得与扩展

欧几里得:

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
", exgcd(a, b, x, y));
23     printf("%d %d
", 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

原文地址:https://www.cnblogs.com/rmy020718/p/9192002.html