欧几里得算法 (辗转相除法)
求最大公约数的一种方法
原理
两个整数的最大公约数等于较小的数和两书之差的最大公约数。
例如:
gcd(1071,462)
=gcd(1071-462=609,462)
=gcd(609-462=147,462)
=gcd(147,462-147=315)
=gcd(147,315-147=168)
=gcd(147,168-147=21)
因为147能整除21,所以最大公约数为21。
上面多次的减运算在程序里可以直接用模运算代替。
实现
#include<stdio.h>
int gcd(int a,int b){
return (b==0)? a:gcd(b,a%b);
}
int main(void){
int a=520,b=2020;
printf("%d\n",gcd(a,b));
return 0;
}
扩展欧几里得
贝祖定理
如果a、b是整数,那么一定存在整数x,y,使得
因为这里用的是递归的方法求的最大公约数,所以求gcd(a,b)之前已经求出了gcd(b,a%b),既现在有两个方程:
所以当递归到b==0时,如果m%a!=0,方程无解,否则最后一条方程有解 (x=m/a,y=0),然后就按上面两条关系递推回去,求出原方程的解。
代码如下:
#include<stdio.h>
int gcd(int a,int b){
return (b==0)? a:gcd(b,a%b);
}
int extent_gcd(int a,int b,int *x1,int *y1,int m){
if(b==0){
if(m%a==0){
*x1=m/a;
*y1=0;
}else{
printf("无解\n");
}
return a;
}
int r,x2,y2;
r=extent_gcd(b,a%b,&x2,&y2,m);
*x1=y2;
*y1=x2-(a/b)*(y2);
return r;
}
int main(void){
int a=520,b=2020;
int x,y;
int m=40;
x=9;y=55555;
printf("%d\n",extent_gcd(a,b,&x,&y,m));
printf("x=%d y=%d\n",x,y);
printf("%d\n",gcd(a,b));
return 0;
}