欧几里得与扩展
欧几里得:
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 }
习题练习:
求关于 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
除特别注明外,本站所有文章均为Manjusaka丶梦寒原创,转载请注明来自出处