1. 程式人生 > 實用技巧 >數論——最大公因數

數論——最大公因數

最大公因數

如果\(u|a,u|b\),而且\(u\)\(a,b\)的共同因數中最大的那個,則稱u是ab的最大公因數,記作\((a,b)=u\)

  • \((a,b)=1\)\(a,b\)互素。
  • 對於\(a_1,a_2...a_n\),若\((a_i,a_j)=1\ (1\leq i<j\leq n)\)則它們兩兩互素。

輾轉相除法

輾轉相除法應該都學過,我們主要說它的數學原理。在這之前先看看演算法。

\[a=bq_1+r_1\\ b=r_1q_2+r_2\\ r_1=r_2q_3+r_3\\ ...\\ r_{n-2}=r_{n-1}q_n+r_n \]

這個\(r_n\)就是最大公因數。

輾轉相除的意思就是,如果\(a,b\)能被\(n\)整除,那麼\(a\mod b\)同樣也能被\(n\)整除。所以(a,b)=(b,r)。所以只要不斷地遞迴求餘,最後一個餘數就是最大公因數。

下面給出C++實現。

// a must > b
int gcd(int a,int b){
	int r;
	while(r!=0){
		r=a%b;
		a=b;
		b=r;
	}
	return a;
}

int main(){
	cout << gcd(20,15) << endl;
}

輾轉相除的意思就是,如果\(a,b\)能被\(n\)整除,那麼\(a\mod b\)

同樣也能被\(n\)整除。所以只要不斷地遞迴求餘,最後一個餘數必是最大公因數。

證明

\[如果 (a,b)=u,那麼\\ \because u|a,u|b\\ \therefore a=su,b=tu\\ \therefore su=tuq+r\\ \therefore r=u(s-tq)\\ \therefore u|r \]

素因式分解

對於每個數,都能分解成若干個素因數的乘積。在找\((a,b)\)的時候,如果我們把\(a,b\)分解成若干素因數的乘積,那麼對尋找最大公因數有些幫助。

\[a=18,b=24\\ a=2\times 3\times 3 = 2^1\times 3^2\\ b=2\times 2\times 2 \times 3=2^2\times 3^1 \]

然後我們分別取每個素因數裡指數最小的那個(必要時可以出現零指數),並乘起來,結果就是最大公因數。

\[(a,b)=2^1\times 3^1 = 6 \]

給出一般公式

\[a=p_1^{a_1}\times p_1^{a_2} \times ... \times p_n^{a_n}\\ b=p_1^{b_1}\times p_1^{b_2} \times ... \times p_n^{b_n}\\ (a,b)=p_1^{min(a_1,b_1)}\times p_2^{min(a_2,b_2)}\times ... \times p_n^{min(a_n,b_n)} \]

使用素因式分解還能尋找最小公倍數。

最小公倍數

如果\(a|c\)\(b|c\),並且\(c\)是所有滿足的整數中最小的那個,\(c\)就稱為\(a,b\)的最小公倍數,記作\([a,b]=c\)

\([4,6]=12\)

素因式分解找最小公倍數

對於最小公倍數,我們只需要選擇素因子列表中指數比較大的那個就好了。

\[a=p_1^{a_1}\times p_1^{a_2} \times ... \times p_n^{a_n}\\ b=p_1^{b_1}\times p_1^{b_2} \times ... \times p_n^{b_n}\\ [a,b]=p_1^{max(a_1,b_1)}\times p_2^{max(a_2,b_2)}\times ... \times p_n^{max(a_n,b_n)} \]

舉個例子

\[a=4,b=6\\ a=2^2,b=2^1\times 3^1\\ [a,b]=2^{max(2,1)}\times 3^{max(1,0)}=2^2\times 3^1=12 \]

最大公因數和最小公倍數之間的線性關係

\[ab=(a,b)\times [a,b] \]

使用素因數分解法不太適合計算機,輾轉相除比較適合計算機,所以求解最小公倍數可以利用這個線性關係。

//lcm是最小公倍數 gcd是使用輾轉相除法實現的最大公因數
function lcm(a,b)
	tmp = gcd(a,b)
	return a*b/tmp

最大公因數線性組合表示

最大公因數總可以以線性組合的方式表示

\[(a,b)=sa+tb \]