第六章 數學問題 -------- 6.5 歐幾里得演算法及其擴充套件
先來看看歐幾里得演算法:
public class Gcd {
/**
* 歐幾里德演算法,即輾轉相除法 最大公約數
*/
public static long gcd(long m, long n) {
return n == 0 ? m : gcd(n, m % n);
}
/**
* 最小公倍數lowest common multiple (LCM)
* 最小公倍數 = a * b / a和b的最大公約數
*/
private static long lcm(long a, long b) {
return a * b / gcd(a, b);
}
}
接著再來看裴蜀(貝祖)等式:對於任何整數a、b和它們的最大公約數d,關於未知數x和y的線性丟番圖方程(稱為裴蜀等式):ax+by = m 有整數解時當且僅當m是d的倍數。x、y可用擴充套件歐幾里得演算法求得。特別地,方程ax+by=1 有整數解當且僅當整數a和b互質。
那什麼是擴充套件歐幾里得演算法呢?
現在我們知道了 a 和 b 的最大公約數是 gcd(a,b) 後面用gcd表示 ,那麼,我們一定能夠找到這樣的 x 和 y ,使得: a*x + b*y = gcd 。這是一個不定方程。那麼,怎麼求出這個特解 x 和 y 呢?只需要在歐幾里德演算法的基礎上加點改動就行了。我們觀察到:歐幾里德演算法停止的狀態是: a= gcd , b = 0 ,那麼,這是否能給我們求解 x y 提供一種思路呢?
首先,將a=gcd,b=0代入原方程,得到gcd*x+0*y=gcd。那麼,這時候,只要x = 1 ,y 是 0 或者其他值(無所謂是多少,反正任何數乘以 0 都等於 0, 但是 x 一定要是 1),這時,我們就會有: a*1 + b*0 = gcd。 當然這是最終狀態,但是我們是否可以從最終狀態反推到最初的狀態呢?
假設當前我們要處理的是求出 a 和 b的最大公約數,並求出 x 和 y 使得 a*x + b*y= gcd ,而我們已經求出了下一個狀態:b 和 a%b 的最大公約數,並且求出了一組x1 和y1 使得: b*x1 + (a%b)*y1 = gcd , 那麼這兩個相鄰的狀態之間是否存在一種關係呢?
首先a可以表示成 a = b*t + k,而 t = a/b(這裡的 “/” 指的是整除),k = a%b ,所以 可以得到a = b*(a/b) +k --> k=a-(a/b)*b --> a%b = a - (a/b)*b,代入 b*x1 + (a%b)*y1 = gcd。
那麼,我們可以進一步得到:gcd = b*x1 + (a-(a/b)*b)*y1
= b*x1 + a*y1 – (a/b)*b*y1
= a*y1 + b*(x1 – a/b*y1)
對比之前我們的狀態:求一組 x 和 y 使得:a*x + b*y = gcd ,是否發現了什麼?
這裡: x = y1
y = x1 – a/b*y1
現在我們找到一組特殊的解 x0 和 y0,那麼,我們就可以用 x0 和 y0 表示出整個不定方程的通解:
x = x0 + (b/gcd)*t ( t 取任意整數)
y = y0 – (a/gcd)*t
如果我們想要得到 x 大於 0 的第一個解的話,那麼表示式就是:
b /= d
x = ( x0%b + b) % b
以上就是擴充套件歐幾里德演算法的全部過程,依然用遞迴寫:
public class ExtGcd {
static long x;
static long y;
public static long gcd(long m, long n) {
return n == 0 ? m : gcd(n, m % n);
}
/**
* 擴充套件歐幾里得
* 呼叫完成後 靜態變數xy是ax+by=m的解
* 返回的還是最大公約數
*/
public static long ext_gcd(long a,long b){
if (b==0) { // 求出了最大公約數 為a
x = 1;
y = 0;
return a;
}
long res = ext_gcd(b, a % b);
//x,y已經被下一層遞迴更新了
long x1 = x;//備份x
x = y;//更新x
y = x1 - a / b * y;//更新y
return res;
}
public static void main(String[] args) {
System.out.println(ext_gcd(2, 7)); // 1
System.out.println(x+" "+y); // -3 1
}
}
最後再來看一下這個線性方程(或者叫二元一次不定方程):ax+by = m 。有整數解時當且僅當m是gcd的倍數。
public static long linearEquation(long a, long b, long m) throws Exception {
long d = ext_gcd(a, b);
//m不是gcd(a,b)的倍數,這個方程無解
if (m % d != 0) {
throw new Exception("無解");
}
long n = m / d;//約一下,考慮m是d的倍數
x *= n;
y *= n;
return d;
}
擴充套件歐幾里德演算法的應用主要有以下兩個方面:
(1)求解不定方程;
(2)求解模線性方程(線性同餘方程)與逆元;
相關文章
- 擴充套件歐幾里得套件
- 第六章 數學問題 -------- 6.7【擴充套件歐幾里得】一步之遙套件
- 淺談擴充套件歐幾里得演算法套件演算法
- 數論學習筆記 (4):擴充套件歐幾里得演算法筆記套件演算法
- 擴充套件歐幾里得演算法公式快速推導套件演算法公式
- [待更新]歐幾里得演算法(輾轉相除法)與擴充歐幾里得演算法演算法
- 尤拉函式、整除分塊和擴充套件歐幾里得函式套件
- 輾轉相除法(歐幾里得演算法)(gcd)模板及其原理演算法GC
- 歐幾里得演算法與 EX演算法
- 萬能歐幾里得演算法演算法
- 類歐幾里得演算法學習筆記演算法筆記
- 求最大公公約數(最大公因數)—— 歐幾里得演算法演算法
- 演算法設計與分析-01歐幾里得演算法
- 數論入門基礎(同餘定理/費馬小定理/擴充套件歐幾里德演算法/中國剩餘定理)套件演算法
- Python如何用歐幾里得求逆元Python
- C++等差數列(數論、歐幾里得輾轉相除gcd)C++GC
- CCF NOI 1028 判斷互質 :利用歐幾里得演算法最大公因數演算法
- 28、(向量)歐幾里得距離計算
- zkw 線段樹-原理及其擴充套件套件
- 斐波那契問題和擴充套件套件
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- Kotlin的幾個擴充套件函式Kotlin套件函式
- Golang浮點數精度丟失問題擴充套件包解決方案Golang套件
- 擴充套件叢集blk數套件
- 數論分塊擴充套件套件
- 洛谷 P6362 平面歐幾里得最小生成樹
- 再學Blazor——擴充套件方法Blazor套件
- 【Kotlin】擴充套件屬性、擴充套件函式Kotlin套件函式
- es6-數值擴充套件套件
- 第六章 數學問題 -------- 6.4 演算法必備求和公式演算法公式
- linux與windows下 安裝 ImageMagick 及其 php imagick擴充套件LinuxWindowsPHP套件
- sql中的擴充套件學習SQL套件
- 歐幾里德的遊戲遊戲
- C#學習筆記-方法引數、擴充套件方法C#筆記套件
- 擴充套件工具套件
- Sanic 擴充套件套件
- Mybatis擴充套件MyBatis套件
- SpringMVC 擴充套件SpringMVC套件