『擴展歐幾里得算法 Extended Euclid』


<更新提示>

<第一次更新>


<正文>

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\)成立。那么

\[ax+by=c \\⇒a'px+b'py=c \\⇒p(a'x+b'y)=c \]

那么\(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\),我們可以構造一組解:

\[\begin{cases} x_n=\frac{c}{p} \\∀y_n\in Z \end{cases} \]

適用於\((a_n,b_n)\),且\((x_n,y_n)\)一定為整數(因為\(p|c\)\(y_n\)取任意整數)。

至此,數學歸納法的底基證明完畢。

由於輾轉相除法,我們可以得知

\[a_n=b_{n-1}\ ① \\b_n=a_{n-1}\%b_{n-1} \\⇒b_n=a_{n-1}-\lfloor a_{n-1}/b_{n-1}\rfloor b_{n-1}\ ② \]

我們剛才已經推得:\(a_nx+b_ny=c\)的一組整數解\((x_n,y_n)\),那么可以把\(①②\)兩式代入\(a_nx+b_ny=c\)得:

\[(b_{n-1})x+(a_{n-1}-\lfloor a_{n-1}/b_{n-1}\rfloor b_{n-1})y=c \]

且對於該方程,解\((x_n,y_n)\)仍適用,即:

\[(b_{n-1})x_n+(a_{n-1}-\lfloor a_{n-1}/b_{n-1}\rfloor b_{n-1})y_n=c \]

成立,可以進行推導:

\[(b_{n-1})x_n+(a_{n-1}-\lfloor a_{n-1}/b_{n-1}\rfloor b_{n-1})y_n=c \\⇒b_{n-1}x_n+a_{n-1}y_n-\lfloor a_{n-1}/b_{n-1}\rfloor b_{n-1} y_n=c \\⇒a_{n-1}y_n+b_{n-1}(x_n-\lfloor a_{n-1}/b_{n-1}\rfloor y_n)=c\ ③ \]

注意到兩項的系數分別為\(a_{n-1},b_{n-1}\),所以對於方程\(a_{n-1}x+b_{n-1}y=c\),通過③式可以直接得到一組解:

\[\begin{cases} x_{n-1}=y_n \\y_{n-1}=x_n-\lfloor a_{n-1}/b_{n-1}\rfloor y_n \end{cases} \]

由此,我們利用輾轉相除法的關系,通過方程\(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})\)

\[\begin{cases} x_{i-1}=y_i \\y_{i-1}=x_i-\lfloor a_{i-1}/b_{i-1}\rfloor y_i \end{cases} \]

由上,數學歸納法完成證明:如果我們得知\(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)\)

\[\begin{cases} x_n=\frac{c}{p} \\∀y_n\in Z \end{cases} \]

在遞歸的回溯過程中,利用公式:

\[\begin{cases} x_{i-1}=y_i \\y_{i-1}=x_i-\lfloor a_{i-1}/b_{i-1}\rfloor y_i \end{cases} \]

倒推每一組\((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);
}

<后記>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM