01-求最大公约数与最小公倍数
前几天,和一哥们聊天,哥们突然提到了求解最大公约数的问题,我不假思索地回答暴力破解啊,哥们呵呵不语,吾顿感不爽,于是有了以下的狂补。
一. 辗转相除法
辗转相除法又名欧几里德算法(Euclidean algorithm)乃求两个正整数之最大公因子的算法。它是已知最古老的算法, 其可追溯至公元前300年前(摘自百度百科)。其具体算法过程如下:假设有正整数a与b,求a与b的最大公约数即是求解b与c=a%b的最大公约数,一致到c为0为止。则最小公倍数既是a与b的乘积除以a与b的最大公约数。不说了上代码。
//--1 迭代版本 --//
#include <iostream>
using namespace std;
int main(void){
int a,b,m,n;
cin>>a>>b;
m =a;
n =b;
int c=a%b;
while(c){
a = b;
b =c;
c = a%b;
}
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b<<endl;
}
//--2 递归版本 --//
#include <iostream>
using namespace std;
int gcd(int m,int n){
if(!(m%n))return(n);
else gcd(n, m%n);
}
int main(void){
int a,b,m,n;
cin>>a>>b;
m =a;
n =b;
b=gcd(m,n);
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b<<endl;
}
二. 辗转相减法
辗转相减法(求最大公约数),即尼考曼彻斯法,其特色是做一系列减法,从而求得最大公约数(摘自百度百科)。这样可以避免如果数字过大时取余带来的不便。算法思想如下,假设有正整数a与b,求a与b的最大公约数即是求解b与c=a-b的最大公约数,一致到c为0为止。则最小公倍数既是a与b的乘积除以a与b的最大公约数。代码如下:
//--1 迭代版本 --//
#include <iostream>
using namespace std;
int main(void){
int a,b,m,n,c;
cin>>a>>b;
m =a;
n =b;
if(a<b){
int t=a;
a =b;
b=t;
}
c = a-b;
while(c){
a = b>c?b:c;
b = b<c?b:c;
c =a-b;
}
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b<<endl;
}
//--2 递归版本 --//
#include <iostream>
using namespace std;
int gcd(int m,int n){
if(m<n){
int t=m;
m =n;
n =t;
}
if(!(m-n))return(n);
else gcd(n, m-n);
}
int main(void){
int a,b,m,n;
cin>>a>>b;
m =a;
n =b;
b=gcd(m,n);
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b<<endl;
}
三. 辗转相减法与辗转相除法相结合
辗转相除法与辗转相减法,各有优缺点又各有长度,为了取其各处的有点,此处将二者结合起来来克服各自的缺点。其算法如下:假设有正整数a与b,若a与b均为偶数,则将a与b均右移一位,并将基数base *2,若a与b仅有一个为偶数,则将a或b右移一位,然后使用辗转相减法,代码如下:
//--1 迭代版--//
#include <iostream>
using namespace std;
int main(void){
int a,b,m,n,c,base=1;
cin>>a>>b;
m =a;
n =b;
a = n<m?m:n;
b = n<m?n:m;
while(a%2 == 0 && b%2 == 0) {
base <<=1;
a >>= 1;
b >>= 1;
}
while(a%2 ==0 ) a >>= 1;
while(b%2 ==0 ) b >>= 1;
int t=a;
a = a<b?b:a;
b = t<b?t:b;
c = a-b;
while(c){
while(a%2 == 0 && b%2 == 0) {
base <<=1;
a >>= 1;
b >>= 1;
}
while(a%2 == 0 ) a >>= 1;
while(b%2 == 0 ) b >>= 1;
a = b>c?b:c;
b = b<c?b:c;
c =a-b;
}
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b*base<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b/base<<endl;
}
//--2 递归版-- //
#include <iostream>
using namespace std;
int gcd(int a, int b){
int t=a, base=1;
a = a<b?b:a;
b = t<b?t:b;
if(a%b ==0) return(b);
else{
while(a%2 == 0 && b %2 ==0 ){
base <<=1;
a >>=1;
b>>=1;
}
while(a%2==0) a>>=1;
while(b%2==0) b>>=1;
t =a;
a = a<b?b:a;
b = t<b?t:b;
return base*gcd(b,a-b);
}
}
int main(void){
int a,b,m,n;
cin>>a>>b;
m = a;
n =b;
b = gcd(a,b);
cout<<m<<"与"<<n<<"最大公约数为:";
cout<<b<<endl;
cout<<m<<"与"<<n<<"最小公倍数为:";
cout<<m*n/b<<endl;
}
本人能力有限,编写的代码比较粗鄙,仅作本人学习所用,如有不正确之处,很高兴您能给指出来。
本文介绍求解最大公约数与最小公倍数的三种算法:辗转相除法、辗转相减法及两者的结合算法。通过C++实现,包括迭代和递归版本。

619

被折叠的 条评论
为什么被折叠?



