1. 程式人生 > >LG 的數學計劃 ---- 第三步 歐幾里得演算法和擴充套件歐幾里得

LG 的數學計劃 ---- 第三步 歐幾里得演算法和擴充套件歐幾里得

於是,我們在完成神奇的前兩步之後,來到了這個神奇的地方——歐幾里得演算法和擴充套件歐幾里得演算法。
那麼,這是用來幹什麼的演算法呢?
算最大公約數(GCD)~~~
好吧,考慮到有一些同學可能還不知道這是怎樣一種神奇的東西,那麼我就把這個東西的定義放到下面來:

最大公因數,也稱最大公約數、最大公因子,指兩個或多個整數共有約數中最大的一個。a和b的最大公約數可以用gcd(a,b)表示

嗯嗯,就是這樣子的

那麼,我們的歐幾里得演算法又是怎麼算這樣一個神奇的東西的呢?

它有一個更加生動的名字叫做輾轉相除法,因為,在我們實際執行的時候就可以發現,它其實就是這樣除來除去的~~~

那麼,我們在做除法的過程中呢,選擇的是帶餘除法,說的簡單粗暴一點,就是計算的結果是商和餘數。

現在,歐幾里得演算法的過程大概如下

設兩數為a、b(a>b),求a和b最大公約數(a,b)的步驟如下:用a除以b,得a÷b=q……r1(0≤r1)。若r1=0,則(a,b)=b;若r1≠0,則再用b除以r1,得b÷r1=q……r2 (0≤r2).若r2=0,則(a,b)=r1,若r2≠0,則繼續用r1除以r2,……如此下去,直到能整除為止。其最後一個為被除數的餘數的除數即為(a, b)。

當然,我們也可以簡化出這樣一種神奇的式子來總結一下gcd(a,b)=gcd(b,a mod b)
嗯,這就是我們歐幾里得演算法的精髓(其實就這一句話,別的都是把你搞暈過去的)

證明如下:(借鑑了一點百度百科)

設兩數為a、b(a>b),用gcd(a,b)表示a,b的最大公約數,r=a mod b 為a除以b的餘數,k為a除以b的商,即a÷b=k.......r。
第一步:令c=gcd(a,b),則設a=mc,b=nc
第二步:根據前提可知r =a-kb=mc-knc=(m-kn)c
第三步:根據第二步結果可知c也是r的因數
第四步:可以斷定m-kn與n互質(假設m-kn=xd,n=yd (d>1),則m=kn+xd=kyd+xd=(ky+x)d,則a=mc=(ky+x)cd,b=nc=ycd,則a與b的一個公約數cd>c,故c非a與b的最大公約數,與前面結論矛盾),因此c也是b與r的最大公約數。
從而可知gcd(b,r)=c,繼而gcd(a
,b)=gcd(b,r)。 證畢。 以上步驟的操作是建立在剛開始時r!=0的基礎之上的。即m與n亦互質。

那麼,我們的程式碼如何實現呢?

int gcd(int a,int b){
    if(b==0)return a;//顯然,這就是遞迴的邊界
    else return gcd(b,a%b);//這也很顯然(其實那個else是可以刪掉的)
}

這樣,gcd函式的返回值就是a和b的最大公約數的值了。

那麼,我們來說說擴充套件歐幾里得是個什麼神奇的東西

首先,擴充套件歐幾里得演算法是用來幹什麼的呢?

其實,是解一種神奇的方程的—>ax+by=gcd(a,b)在這裡,a和b是常數,我們需要求出x,y的值使之成立。啊………

那麼,它的用處也很明顯了:求解線性模方程和方程組。

(當然這只是大多數用處)

那麼,程式碼如下

#include<bits/stdc++.h>
using namespace std;
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    int rec=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return rec;
}
int main(){
    int i,j,k,m,n,a,b,x,y;
    cin>>a>>b;
    cout<<exgcd(a,b,x,y)<<endl;
    cout<<x<<" "<<y<<endl;
    return 0;
}

顯然,神奇的程式碼就在這裡了,由於和樸素的歐幾里得演算法沒有什麼新的難的地方(當然樸素的也沒有什麼難的),證明過程和詳細的註釋就省略了~

好了,我們 LG的數學計劃 第三步就這麼愉快的結束了,拜拜~~
第四步 神奇的傳送門(當然現在這是我自己的了)
:)

當然你也可以選擇訪問LYQ的文章傳送到神奇的LYQ

大家下一步再見咯~