最小公倍数和最大公约数之小结

      今天看了HDOJ上的1019题,题目的核心在于求两个数的最小公倍数(lowest common multiple),我想既然看到了这个题目,就把相关求两个数最小公倍数和最大公约数(greatest common divisor)之类的东西总结一下吧,于是就有了这篇文章,文章中参考了部分网络上的资源,尤其是求最大公约数的欧几里德算法,感谢。

首先说明下求最大公约数的欧几里德算法,也叫辗转相除法,如下:

欧几里德算法(辗转相除法),用于计算两个整数a,b的最大公约数。

其计算原理依赖于下面的定理:

定理:gcd(a,b) = gcd(b,a mod b)

证明:a可以表示成a = kb + r,则r = a mod b

一方面,假设da,b的一个公约数,则有 d|a, d|b,而r = a - kb,因此d|r

因此d(b,a mod b)的公约数

另一方面,假设d (b,a mod b)的公约数,则d | b , d |r ,但是a = kb + r

因此d也是(a,b)的公约数

因此(a,b)(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证!

(注 x|yy可以被x整除,即 y mod x == 0

因此,求ab的最大公约数就相当于求 ba%b的最大公约数,如此循环下去,直到a mod b为零为止,因为如果a mod b为零的话,就说明gcd(a,b) = b了,结束。可根据上述算法描述写出程序如下:(分为递归和非递归)

// 递归算法
int  gcd_recursive( int  a, int  b)
{
    
int temp;
    
if(a < b)
    
{
        temp 
= a;
        a 
= b;
        b 
= temp;
    }

    
if(b == 0)
        
return a;
    
else
        
return gcd_recursive(b,a%b);
}

 

// 非递归算法
int  gcd_non_recursive( int  a, int  b)
{
    
int r;
    r 
= a%b;
    
while(r != 0)
    
{
        a 
= b;
        b 
= r;
        r 
= a%b;
    }

    
return b;
}

求两个数的最小公倍数可以如下计算:用两个数的乘积除以两个数的最大公约数就可以了.程序如下:

// 求两个数的最小公倍数
// 方法:两个数的乘积除以两个数的最大公约数
// 即:lcm = a*b/gcd(a,b)
int  lcm( int  a, int  b)
{
    
return a*(b/gcd_recursive(a,b));
}

在杭电的1019题目中,题目的本意是要求一系列数的最小公倍数,其实这完全可以通过递归来达到要求,求一系列数的最大公约数的原理也是一样的,程序如下:

// 如果是求一系列数的最大公约数,那么就可以采用递归方式从最后一个数开始
// 逐个计算一个数组的最后一个数a[n-1]和前n-1个数的最大公约数就可以了
// 以下的求一系列数的最小公倍数道理相同
int  gcd_n( int   * a, int  n)
{
    
if(n == 1)
        
return *a;
    
else
        
return gcd_recursive(a[n-1],gcd_n(a,n-1));
}


int  lcm_n( int   * a, int  n)
{
    
if(n == 1)
        
return *a;
    
else
        
return lcm(a[n-1],lcm_n(a,n-1));
}

 结.

你可能感兴趣的:(小结)