歐幾里得演算法(求最大公因子)及擴充套件歐幾里得(求乘法逆元)
一、歐幾里得演算法
歐幾里得演算法又稱輾轉相除法,是指用於計算兩個正整數a,b的最大公約數。gcd(a,b)=gcd(b,a mod b)。
演算法描述:
1. 輸入:兩個非負整數a,b,且a≥b。
2. 輸出:a,b的最大公因子。
(1)當b≠0時,作
r←a mod b,a←b,b←r。
(2) 返回(a)。
程式碼遞迴實現:
int gcd(int a,int b) { //如果a小於b if(a<b) { int temp=a; a=b; b=temp; } if(b==0)return a; else return gcd(b,a%b);//遞迴 }
二、擴充套件歐幾里得演算法
擴充套件歐幾里德演算法是用來在已知a, b求解一組x,y,使它們滿足貝祖等式: ax+by = gcd(a, b) =d(解一定存在,根據數論中的相關定理)。
遞推演算法:
輸入:兩個非負整數a,b且a≥b。
輸出:d=gcd(a,b)與滿足ax+by=d的整數x與y。
1. 若b=0,則d←a,x=1,y=0,返回(d,x,y)。
2. 設x2←1,x1=0,y2=1,y1=1。
3. 當b>0時,作
(1) q←a/b,r←a-qb,x←x2-qx1,y←y2-qy1。
(2) a←b,b←r,x2←x1,x1←x,y2←y1,y1←y。
4. d←a,
遞迴演算法推導:
設 a>b。
1,顯然當 b=0,gcd(a,b)=a。此時 x=1,y=0;
2,a>b>0 時
設 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根據樸素的歐幾里德原理有 gcd(a,b) = gcd(b,a mod b);
則:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
說明: a-[a/b]*b即為mod運算。[a/b]代表取小於a/b的最大整數。
也就是
根據恆等定理得:x1=y2; y1=x2- [a / b] *y2;
這樣我們就得到了求解 x1,y1 的方法:x1,y1 的值基於 x2,y2.
上面的思想是以遞迴定義的,因為 gcd 不斷的遞迴求解一定會有個時候 b=0,所以遞迴可以結束。
乘法逆元:
若gcd(r,m)=1,則存在整數s,使得rs≡1(mod m) 。整數s也稱為r模整數m下的乘法逆元。那麼當gcd(a,b)=1,有ax+by = gcd(a, b)=1,那麼通過計算得出(b+x%b)%b的值就是a在b模下的乘法逆元。
遞推程式碼實現:
int gcd(int a,int b)
{
//如果a小於b
if(a<b)
{
int temp=a;
a=b;
b=temp;
}
if(b==0)return a;
else return gcd(b,a%b);//遞迴
}
int ex_Gcd(int a,int b,int &x,int &y)
{
int x1=0,x2=1,y1=1,y2=0,q,d,r;
//最大公因子
d=gcd(a,b);
if(b==0)
{
d=a;
x=1;
y=0;
return d;
}
while(b>0)
{
q=a/b;
r=a-q*b;
x=x2-q*x1;
y=y2-q*y1;
a=b;
b=r;
x2=x1;
x1=x;
y2=y1;
y1=y;
}
d=a;
x=x2;
y=y2;
return d;
}
int main()
{
int x,y;
int a,b;
cin>>a>>b;
ex_Gcd(a,b,x,y);
if(gcd(a,b)==1)
{
cout<<"存在a的乘法逆元:"<<(b+x%b)%b<<endl;
}else{
cout<<"不存在a的乘法逆元!"<<endl;
}
cout<<"x:"<<x<<endl;
cout<<"y:"<<y<<endl;
return 0;
}
遞迴程式碼實現:
int gcd(int a,int b)
{
//如果a小於b
if(a<b)
{
int temp=a;
a=b;
b=temp;
}
if(b==0)return a;
else return gcd(b,a%b);//遞迴
}
int ex_Gcd(int a, int b, int& x, int& y)
{
int d;
if(b!=0){
d = ex_Gcd(b, a % b, y, x);
//cout<<"a:"<<a<<endl;
//cout<<"b:"<<b<<endl;
//cout<<"x:"<<x<<endl;
// cout<<"y:"<<y<<endl<<endl<<endl;
y = y-(a / b) * x;
}else {
x = 1;
y = 0;
}
return d;
}
int main()
{
int x,y;
int a,b;
cin>>a>>b;
ex_Gcd(a,b,x,y);
if(gcd(a,b)==1)
{
cout<<"存在a的乘法逆元:"<<(b+x%b)%b<<endl;
}else{
cout<<"不存在a的乘法逆元!"<<endl;
}
cout<<"x:"<<x<<endl;
cout<<"y:"<<y<<endl;
return 0;
}