<更新提示>
<第一次更新>
<正文>
Euclid算法(gcd)
在學習擴展歐幾里得算法之前,當然要復習一下歐幾里得算法啦。
眾所周知,歐幾里得算法又稱gcd算法,輾轉相除法,可以在\(O(log_2b)\)時間內求解\((a,b)\)(a,b的最大公約數)。
其核心內容可以陳述為:\((a,b)=(b,a\%b)\),然后反復迭代該式縮小\(a,b\)規模,直到\(b=0\),得到a為最大公約數。
證明
設兩數為\(a\ b(b<a)\),求它們最大公約數的步驟如下:用\(b\)除\(a\),即\(a/b=q…..r\),得\(a=bq+r(0≤r<b)\),即為余數,\(q\)是這個除法的商)。若\(r=0\),則\(b\)是\(a\)和\(b\)的最大公約數,\(a\),\(b\)存在倍數關系。若\(r≠0\),則繼續考慮。
首先,應該明白的一點是任何 \(a\) 和 \(b\) 的公約數都是 \(r\) 的公約數。要想證明這一點,就要考慮把 \(r\) 寫成 \(r=a-bq\)。現在,如果 \(a\) 和 \(b\) 有一個公約數 \(d\),而且設 \(a=sd , b=td\), 那么 \(r = sd-tdq = (s-tq)d\)。因為這個式子中,所有的數(包括 \(s-tq\))都為整數,所以 \(r\) 可以被 \(d\) 整除。
對於所有的 \(d\) 的值,這都是正確的。所以 \(a\) 和 \(b\) 的最大公約數也是 \(b\)(因為\(b< a\),所有取b繼續運算才能不斷縮小規模,直至兩數有倍數關系) 和 \(r\) 的最大公約數。因此我們可以繼續對 \(b\) 和 \(r\) 進行上述取余的運算。這個過程在有限的重復后,可以最終得到 \(r=0\) 的結果,我們也就得到了 \(a\) 和 \(b\) 的最大公約數
實現
\(Code:\)
inline int Euclid(int a,int b){return b==0?a:Eucild(b,a%b);}
Extended Euclid算法(exgcd)
那么接下來就是擴展歐幾里得啦。
正如其名,擴展歐幾里得算法就是基於歐幾里得算法的擴展運用。該算法用於解決一下模型的問題:
求解關於\(x,y\)的二元不定方程\(ax+by=c\)的整數解
在講解算法之前,需要先了解該算法的核心,即裴蜀定理:
對任何整數\(a,b\),關於未知數x和y的線性丟番圖方程(稱為裴蜀等式):\(ax+by=c\),方程有整數解當且僅當\(c\)是\((a,b)\)的倍數。裴蜀等式有解時必然有無窮多個解。
證明
1.必要性證明:如果有整數解,則\(c\)是\(p\)的倍數
令\(p=(a,b)\),設\(a=a'p\),\(b=b'p\),則有\((a',b')=1\)成立。那么
那么\(c\)就是\(p\)的一個因數,所以\(p|c\)得證。
2.充分性證明:如果\(c\)是\(p\)的倍數,則\(ax+by=c\)有整數解
令\(p=(a,b)\),記歐幾里得算法中每一次輾轉得到的數對為\((a_1,b_1),(a_2,b_2),...,(a_n,b_n)\),其中,\((a_1,b_1)\)即為\((a,b)\),\((a_n,b_n)\)即為\((p,0)\),符合輾轉相除法的流程。
對於\((a_n,b_n)\),求方程\(a_nx+b_ny=c\)的解,由於\(a_n=p,b_n=0\),我們可以構造一組解:
適用於\((a_n,b_n)\),且\((x_n,y_n)\)一定為整數(因為\(p|c\),\(y_n\)取任意整數)。
至此,數學歸納法的底基證明完畢。
由於輾轉相除法,我們可以得知
我們剛才已經推得:\(a_nx+b_ny=c\)的一組整數解\((x_n,y_n)\),那么可以把\(①②\)兩式代入\(a_nx+b_ny=c\)得:
且對於該方程,解\((x_n,y_n)\)仍適用,即:
成立,可以進行推導:
注意到兩項的系數分別為\(a_{n-1},b_{n-1}\),所以對於方程\(a_{n-1}x+b_{n-1}y=c\),通過③式可以直接得到一組解:
由此,我們利用輾轉相除法的關系,通過方程\(a_nx+b_ny=c\)的一組解\((x_n,y_n)\),推得了方程\(a_{n-1}x+b_{n-1}y=c\)的一組解\((x_{n-1},y_{n-1})\)。
同樣地,我們可以由\((x_i,y_i)\)的一組解,得到方程\(a_{i-1}x+b_{i-1}y=c\)的一組解\((x_{i-1},y_{i-1})\)
由上,數學歸納法完成證明:如果我們得知\(a_nx+b_ny=c\)的一組解\((x_n,y_n)\),且\((a_1,b_1),(a_2,b_2),...,(a_n,b_n)\)是由輾轉相除法得到的序列,那么我們就可以通過以上方法得到原方程\(a_1x+b_1y=c\)的解\((x_1,y_1)\)。
然而,我們已經通過構造法得到\(a_nx+b_ny=c\)的一組解\((x_n,y_n)\),且保證c是p的倍數時,整數解\((x_n,y_n)\)一定存在。故c是p的倍數時,方程\(ax+by=c\)一定有整數解。充分性得證。
實現
回歸正題,看擴展歐幾里得算法。
千萬不要想着不看證明咯。裴蜀定理的充分性證明過程就是擴展歐幾里得算法的流程。
先由輾轉相除法求解\((a,b)\),得到\(p=(a,b)\)
同時,構造解\((x_n,y_n)\)
在遞歸的回溯過程中,利用公式:
倒推每一組\((a_i,b_i)\)的解\((x_i,y_i)\)。
最后得到\((a,b)\)和原方程\(ax+by=c\)的一組解\((x,y)\)。
至此,擴展歐幾里得算法完成。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
inline int Extended_Euclid(int a,int &x,int b,int &y,int c)
{
if(b==0){x=c/a,y=0;return a;}
else
{
int p=Extended_Euclid(b,x,a%b,y,c);
int x_=x,y_=y;
x=y_; y=x_-a/b*y_;
return p;
}
}
int main(void)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int p,x,y;
p=Extended_Euclid(a,x,b,y,c);
printf("(%d,%d)=%d\n",a,b,p);
printf("x=%d,y=%d\n",x,y);
}
<后記>