1. 程式人生 > 實用技巧 >擴充套件歐幾里得演算法(exgcd)

擴充套件歐幾里得演算法(exgcd)

擴充套件歐幾里得演算法,是用來求形如

\[ax+by=c \]

的不定方程的整數解的。

判斷是否有整數解

根據裴蜀定理,若 \(gcd(a,b) \mid c\),則一定有整數解,否則一定無解。

證明

\(d=gcd(a,b)\),顯然有 \(d \mid a,d \mid b\)。由於 \(x,y\) 都是整數,所以 \(d \mid (ax),d \mid (by)\)
所以如果要讓式子成立,\(c\) 必須得是 \(a,b\) 的公約數的倍數才對。
又因為 \(x,y\) 是整數,所以 \(c\) 必須是 \(a,b\) 的最大公約數的倍數才行。
實在看不懂的話感性理解下吧awa

轉化

讓方程兩邊同除以 \(gcd(a,b)\),可以得到方程

\[a'x+b'y=c' \]

其中

\[a'=a \times \frac{gcd(a,b)}{c},b'=b \times \frac{gcd(a,b)}{c},c'=c \times \frac{gcd(a,b)}{c}=gcd(a,b) \]

後面求特解中提到的方程均為轉化後的方程,即後面方程中的 \(a\) 就是 \(a'\)\(b\) 就是 \(b'\)

求解

求特解

由歐幾里得演算法可知,\(gcd(a,b)=gcd(b,a \bmod b)\)
於是,我們可以得到

\[bx'+(a \bmod b)y'=gcd(b,a \bmod b) \]

接下來我們就要根據 \(x',y'\) 來反推 \(x,y\)
因為 \(gcd(a,b)=gcd(b,a \bmod b)\),所以

\[ax+by=bx'+(a \bmod b)y' \]

我們把右邊的式子變形一下:

\[bx'+(a \bmod b)y' \]

\[=(a-b\left\lfloor\frac{a}{b}\right\rfloor)y'+bx' \]

\[=ay'+bx'-b\left\lfloor\frac{a}{b}\right\rfloor y' \]

\[= ay'+b(x'-\left\lfloor\frac{a}{b}\right\rfloor y') \]

所以,\(x=y',y=x'-\left\lfloor\frac{a}{b}\right\rfloor y')\)


於是我們只要向歐幾里得演算法那樣遞迴,就能得到一組特解了。
但還有一個問題,就是遞迴邊界。
遞迴邊界顯然是 \(b=0\) 的情況,而此時的方程就變為:

\[ax+by=ax=gcd(a,0)=a \]

所以此時 \(x=1\)\(y\) 是任意整數。

求解過程用程式碼寫出來就是這個亞子:

ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1;
		y=0;//y可以是任意整數,這裡我們讓他等於0也可以
		return a;
	}
	const ll m=exgcd(b,a%b,y,x);
	y-=(a/b)*x;
	return m;
}

但是但是,這求的是

\[ax+by=gcd(a,b) \]

的解呀。不是我們要的解。
因為我們在轉化時讓方程兩邊都除以 \(\frac{c}{gcd(a,b)}\),所以現在要乘回來:

\[x=x \times \frac{c}{gcd(a,b)},y=y \times \frac{c}{gcd(a,b)} \]

求通解

這裡我們設之前求出來的通解為 \(x_0,y_0\)
\(d=gcd(a,b)\)
則通解

\(x=x_0+\frac{b}{d} \times t,y=y0-\frac{a}{d} \times t\)

t是任意整數。
為什麼是這樣呢?
顯然我們需要滿足

\[ax+by=c \]

\(x,y\) 拆開來:

\[a(x_0+n)+b(y_0-m)=c \]

於是就有

\[an-bm=0 \]

又因為 \(n,m\) 必須是整數,所以只有上面說的那個可以滿足要求了。

求最小正整數解

這裡指 \(x\) 是最小正整數。
當我們求出一組特解後,最小正整數解即

\[x=(x_0%b+b)%b,y=(c-ax)/b \]

上面的式子用的是 C++ 語法。
求最小正整數解慣用手法,這裡不再累述。