淺談擴展歐幾里得(擴展GCD)算法
本篇隨筆講解信息學奧林匹克競賽中數論部分的擴展歐幾里得算法。為了更好的閱讀本篇隨筆,讀者最好擁有不低於初中二年級(這是經過慎重考慮所評定的等級)的數學素養。並且已經學會了學習這個算法的前置知識:歐幾里得算法。
對於對歐幾里得算法還有知識模糊的讀者,請不要擔心,這里為你准備了前導知識講解,請移步至本蒟蒻的另兩篇博客:
裴蜀定理
裴蜀定理的概念及證明
因為翻譯版本的不同,這個定理可能還會被叫做貝祖定理、\(B\acute{e}zout\)定理等。
裴蜀定理是這樣被描述的:
滿足:
文字描述是這樣的:對於任意的整數\(a,b\),都存在一對整數\(x,y\),使得\(ax+by=\gcd(a,b)\)成立。
證明:
來看歐幾里得算法求解過程的這個函數:
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
可以看出,這是一個遞歸求解的函數。在函數遞歸到最后的時候,存在\(b=0\),不管\(a\)是什么,這時顯然有一對整數\(x=1,y=0\)來使得:
(ps:0和任何數的最大公約數都等於原數,可以從最大公約數和約數的定義得知)
那么,我們通過這個遞歸的實現過程來進行回溯的模擬。當\(b>0\),則程序還可以繼續往下走:\(\gcd(b,a\%b)=\gcd(a,b)\)。這時假設存在一對整數\(x,y\),使得其一定會滿足\(b\times x+(a\%b)\times y=\gcd(b,a\%b)\), 因為\(a\%b=a-b\lfloor a/b\rfloor\),所以有以下的推導:
這個時候令\(x^{'}=y,y^{'}=x-\lfloor a/b\rfloor y\),再結合一開始的原式子,就得出:
因為歐幾里得算法的實現是遞歸的,而我們已經推出其中一個遞歸過程的實現,那么其他的遞歸過程就可以借助數學歸納法,一層層地向上推,必然會得出最終結論。
證畢。
裴蜀定理的應用
裴蜀定理:
那么可以推出:如果一個數\(m\)滿足:\(ax+by=m\),那么這個\(m\)一定是\(\gcd(a,b)\)的倍數。
那么對於一個經典方程\(ax+by=1\),利用裴蜀定理,我們有:\(\gcd(a,b)=1\),即\(a,b\)一定互質。
擴展歐幾里得算法
在介紹擴展歐幾里得算法之前,我想首先介紹它的應用:
1、求解不定方程
2、求解模的逆元
3、求解線性同余方程
為什么它能應用到這幾個方面呢?回到裴蜀定理:
對於這個不定方程,如果存在一組合法的解\((x,y)\),那么一定會有\(\gcd(a,b)|m\),即\(m\)是\(\gcd(a,b)\)的倍數。那么現在我不僅想知道到底有沒有解,而是想知道在有解的情況下,這個解到底是多少。
這就是求解不定方程的過程。這個解決的算法就叫做擴展歐幾里得算法。
可以發現,我們求解不定方程其實就是要求解一組合法的\((x,y)\),那么根據裴蜀定理的證明(基於歐幾里得算法,采用遞歸的數學歸納),可以發現\(x,y\)的互相推導的關系。
這種采取遞歸來求解\(x,y\)的方法就叫做擴展歐幾里得算法。
擴展歐幾里得算法的實現:
先放板子:
int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int k=x;
x=y;
y=k-a/b*y;
return d;
}
擴展歐幾里得算法的實現基於裴蜀定理的證明。實質上相當於在做歐幾里得算法(普通GCD)的時候對不定方程\(ax+by=m\)的\(x,y\)也做了更改。所以經過擴展歐幾里得算法處理過的\(x,y\)就已經是一組合法的可行解了。
這里需要注意一個細節,因為擴展GCD需要對\(x,y\)本身進行修改,所以需要在傳參數的時候加取址符,這樣能保證被修改。
