上网了看了下别人的程序,着实学了不少。
解法一:欧几里得辗转相除法:
f(x,y) = GCD(x,y), 取k = x / y, b = x % y,则:x = k*y + b;
如果一个数能整除x,y,则它也能整除b,y;
而且能整除b,y的数必能整除x,y,即x,y和b,y的公约数是相同的,其最大公约数也是相同的,即f(x,y) = f(y ,x %
y) (x>=y>0)
递归实现:
#include
int GCD(int a,int b)
{
if(b ==
0){
return
a;
}
else{
//a,b和b,a%b有相同的最大公约数
return
GCD(b,a%b);
}
}
int main(){
int
a,b;
scanf("%d
%d",&a,&b);
printf("%d\n",GCD(a,b));
}
非递归实现:
#include
int GCD(int a,int b)
{
int temp =
a;
while(b){
a = b;
b = temp %
b;
}
return
a;
}
int main(){
int
a,b;
scanf("%d
%d",&a,&b);
printf("%d\n",GCD(a,b));
}
解法二:取模运算,如果是大整数的话,计算开销非常大,尽量避免。
分析:一个数能整除x,y则必能同时整除x - y,y。能同时整除x - y,y
则必能同时整除x,y。即x,y的公约数和x-y,y的公约数是一样的,其最大公约数也是一样的。这样子程序中将上面两个解法中的除法化为减法,不过遇到两个数字相差很大时就比较复杂了,比如说1000000000,1,这样子就要减很多次才能得出结果。
#include
int GCD(int a,int b)
{
if(a
< b){
return
GCD(b,a);
}
if(b ==
0){
return
a;
}
else{
return GCD(a
- b,b);
}
}
int main(){
int
a,b;
scanf("%d
%d",&a,&b);
printf("%d\n",GCD(a,b));
}
在网上还看到更加神奇的解法,想到计算机组成原理里说过,乘除法可以通过移位来实现的,节约大量的计算时间。(copy下分析)
分析:
对于x,y,如果y = k * y1,x = k * x1,则f(y,x) = K*f(x1,y1);
如果x = p * x1, 假设p是素数,且 y % p != 0 ,即y不能被p整除,则f(x,y) =
f(x1,y).
2是典型的素数,而乘以2、除以2其实就是二进制表示数时的移位操作,利用2来解决这个题目:
若x,y都为偶数(2肯定是公约数),则f(x,y) = 2*f(x / 2,y /
2) =
2*f(x>>1,y>>1);
若x为偶数,y为奇数(2肯定不是公约数),则f(x,y) =
f(x / 2, y / 2) = f(x>>1, y)
若x为奇数,y为偶数2肯定不是公约数),则f(x,y)= f(x, y / 2) =
f(x, y>>1)
若x,y都为奇数(2肯定不是公约数),则f(x,y) = f(y, x-y)
(x-y肯定为偶数) = f(y,
(x-y)/2)
这个方法的程序实现,我就没有自己敲了,COPY下网上的,借鉴下:
#include
//判断奇偶性
int IsEvenOdd(int n){
if(n % 2 ==
0){
return
1;
}
else{
return
0;
}
}
int GCD(int a,int b)
{
//如果a
< b
if(a
< b){
return
GCD(b,a);
}
if(b ==
0){
return
a;
}
//若x,y都为偶数
if(IsEvenOdd(a) == 1 &&
IsEvenOdd(b) == 1){
return 2 *
GCD(a>>1,b>>1);
}
//若x,y都为奇数
else
if(IsEvenOdd(a) == 0 &&
IsEvenOdd(b) == 0){
return
GCD(b,a-b);
}
//若x是偶数y是奇数
else
if(IsEvenOdd(a) == 1 &&
IsEvenOdd(b) == 0){
return
GCD(a>>1,b);
}
//若x是奇数y是偶数
else{
return
GCD(a,b>>1);
}
}
int main(){
int
a,b;
scanf("%d
%d",&a,&b);
printf("%d\n",GCD(a,b));
}
睡觉,晚安。