擴充套件歐幾里得演算法(乘法逆元 最小正整數解 直線上的整數點)
參考資料:
本文證明過程來自百度百科和劉汝佳的演算法入門經典。
擴充套件歐幾里得演算法介紹:
前置知識:歐幾里得演算法(其實就是輾轉相除法,用於計算兩個整數a,b的最大公約數。)
歐幾里得演算法:
在開始之前,我們先說明幾個定理:
gcd(a,b)=gcd(b,a)=gcd(-a,b)=gcd(|a|,|b|)
公式表述及證明
gcd(a,b)=gcd(b,a mod b)
證明:a可以表示成a = kb + r,則r = a mod b
假設d是a,b的一個公約數,則有
d|a, d|b,而r = a - kb,因此d|r
因此d是(b,a mod b)的公約數
假設d 是(b,a mod b)的公約數,則
d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公約數
因此(a,b)和(b,a mod b)的公約數是一樣的,其最大公約數也必然相等,得證
程式碼:
根據上述公式,我們可以用遞迴來實現GCD函式(邊界條件就是a,b的最大公約數是b本身的時候,也就是a%b==0的時候),程式碼如下:
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
擴充套件歐幾里得演算法:
擴充套件歐幾里德演算法是歐幾里得演算法的擴充套件,是用來在已知a, b的情況下求解一組x,y,使它們滿足貝祖等式: ax+by = gcd(a, b) =d(解一定存在,根據數論中的相關定理)。擴充套件歐幾里德常用在求解模線性方程及方程組中。
注意:很容易忽略的一個地方:對於不全為0的非負整數a,b(擴充套件歐幾里得演算法要求傳入的引數a,b是非負的),gcd(a, b)表示a, b的最大公約數,必定存在整數對x,y,滿足a*x+b*y==gcd(a, b)。如果有引數含有負數,則需要特殊處理,處理方式如下:(來自維基百科)
求解 x,y的方法及證明 (設 a>b)
1,顯然當 b=0,gcd(a,b)=a。此時 x=1,y=0;
2,a>b>0 時,設 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根據樸素的歐幾里德原理有 gcd(a,b) = gcd(b,a mod b);
則:ax1+ by1= bx2+ (a mod b)y2;
即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
說明: a-[a/b]*b即為mod運算。[a/b]代表取小於a/b的最大整數。
也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
根據恆等定理得:x1=y2; y1=x2- [a / b] *y2;
這樣我們就得到了求解 x1,y1 的方法:x1,y1 的值基於 x2,y2.
上面的思想是以遞迴定義的,因為 gcd 不斷的遞迴求解一定會有個時候 b=0,所以遞迴可以結束。
遞迴邊界:gcd(a,0)=1*a-0*0=a。
程式碼實現一:
int exGcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;y=0;
return a;
}
int r=exGcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;
return r;
}
程式碼實現二(推薦):
int exGcd(int a,int b,int &d,int &x,int &y)
{
if(!b) { d=a;x=1;y=0; }
else { gcd(b,a%b,d,y,x); y-= x*(a/b); }
}
擴充套件歐幾里得演算法的應用:
應用一:求解乘法逆元(A和MOD互素的時候才存在,否則不存在逆元)
首先同餘模定理如下:
(a+b)%c=(a%c+b%c)%c;
(a*b)%c=(a%c*b%c)%c;
也就是說對於取模的加減法,和乘法我們都可以運用同餘模定理來進行計算,那麼,對於除法我們應該怎麼辦呢?首先想到的就是把除法轉換成乘法,然後就可以運用定理了。怎麼轉換呢,在普通乘法中,我們知道,除以一個數就等於乘上一個數的倒數,其實這個倒數就是我們所謂的逆元。A*(A的逆元)=單位元。在普通的乘法中 A的逆元就是它的倒數。 那麼,在模n乘法中,我們應該怎麼求逆元呢?我們設A的逆元為X,那麼我們就可以得到(A*X)%MOD=1(模n乘法的單位元也是1)。對這個式子進行變形 ,就可以得到:
(A*X)%MOD=1;那麼肯定存在k使得
A*X=k*MOD+1;
移項可得:A*X-k*MOD=1;
所以,當A和MOD互素時,就可以寫成
A*X-k*MOD=gcd(A,MOD);
如果把A看做a,MOD看做b,X看做x,-k看做y的話,則上式可化為:
ax+by=gcd(a,b);
這樣就可以用擴充套件歐幾里得演算法求出來x了,也就是我們要找的逆元。
應用二:求解ax=c(mod b)(也就是ax+by=c(同上逆元的變化方式))的x的最小整數解
ax=c(mod b)可以轉化為ax+by=c。(變化的方式同求逆元的時候的變化。)
我們可以用擴充套件歐幾里得演算法得出ax+by=gcd(a,b) 的一組解(x1,y1),那麼其他解呢?任取另一組解(x2,y2),則ax1+by1=ax2+by2(因為它們都等於gcd(a,b) ),變形得a(x1-x2)=b(y2-y1)。假設gcd(a,b)=g,方程左右兩邊同時除以g(如果g=0,說明a或b等於0,可以特殊判斷),得a'(x1-x2)=b'(y2-y1),其中a'=a/g,b'=b/g。注意,此時a'和b'互素(想想分數的化簡),則因此x1-x2一定是b'的整數倍(因為a'中不包含b',所以x1-x2一定包含b')。設它為kb',計算得y2-y1=ka'。注意,上述的推導過程並沒有用到“ax+by的右邊是什麼”,因此得出以下結論:
設a,b,c為任意整數,若方程ax+by=c的一組解是(x0,y0),則它的任意整數解都可以寫成(x0+kb',y0-ka'),其中a'=a/gcd(a,b),b'=b/gcd(a,b),k取任意整數。
這樣我們就可以求出來最小的整數解了。(先用擴充套件歐幾里得演算法求出一組解,然後進行變換)。
具體實現方式看程式碼的註釋:
int cal(int a,int b,int c)
{
int x,y;
int gcd=(a,b,x,y);
if(c%gcd!=0)
return -1;//代表無解
// ax0+by0=gcd(a,b) 方程一
//同時乘以c/gcd(a,b)得
// (a*c/gcd(a,b))*x0+(b*c/gcd(a,b))*y0=c;
// 令 x1=c/gcd(a,b)*x0 y1=c/gcd(a,b)*y0;
// 則可得 ax1+by1=c 方程二
// 這時得出方程的一個解 x1=x0*c/gcd(a,b) y1=y0*c/gcd(a,b)
x*=c/gcd; //將 方程一的一個特解轉化成方程2的一個特解
//套用上文的公式可得對方程二
// b'=b/gcd(a,b);
b/=gcd;
if(b<0)//處理小於0的特殊情況
b=-b;
//對特解x +- kb' 找到最小整數解
//設x=kb'+r
//那麼我們想要求的整數解就是r
//直接取模運算即可
int ans=x%b;
//把負數的r轉化成正數的
if(ans<=0)
ans+=b;
return ans;
}
應用三:直線上的整數點
在平面座標系下,ax+by=c是一條直線方程。知道一個點,我們就可以用應用二中的方法去求直線上的所有整數點。
END~
相關推薦
擴充套件歐幾里得演算法(乘法逆元 最小正整數解 直線上的整數點)
參考資料: 本文證明過程來自百度百科和劉汝佳的演算法入門經典。 擴充套件歐幾里得演算法介紹: 前置知識:歐幾里得演算法(其實就是輾轉相除法,用於計算兩個整數a,b的最大公約數。) 歐幾里得演算法: 在開始之前,我們先說明幾個定理: gcd(a,b)=gcd(b,a
擴充套件歐幾里德演算法求乘法逆元(C語言版)
#include <stdio.h> int ExtendedEuclid( int f,int d ,int *result); int main() { int x,y,z; z = 0; printf("輸入
擴充套件歐幾里得演算法及求逆元
師父的擴充套件歐幾里得演算法詳細部落格師父喲 大神的求逆元詳細部落格大神的呢 gcd(a,b)即求a和b的最大公約。用輾轉相除法求得。 擴充套件歐幾里得演算法是歐幾里得演算法(又叫輾轉相除法)的擴充套件。除了計算a、b兩個整數的最大公約數,此演算法還能找到
歐幾里德演算法、擴充套件歐幾里德演算法、乘法逆元
最近看了一本書《程式設計師》裡面說的一個面試題: 求兩個數的最大公約數: SoEasy的題目看過C 的人都知道怎麼寫這個程式 1.傳統方法:窮舉 #include <math.h>int main(){int m=1970,n=1066,p=0;p=m<n?m:n;for(;p>=1
擴充套件歐幾里得演算法(求乘法逆元)
eg:求5關於模14的乘法逆元 15 = 5*2+1 5 = 4*1+1 說明5與14互素,存在5關於14的乘法逆元 1 = 5-4 = 5-(14-5*2)= 5*3-14 因此5關於模14的乘法逆元為3 a存在模b的乘法逆元的充要條件是gcd(a,b)= 1 互質
演算法複習——擴充套件歐幾里得演算法(擴充套件歐幾里得,逆元,整除)
①歐幾里得演算法 就是求gcd的有趣的輾轉相除法,不再贅述啦0v0 程式碼: int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); } ②擴充套件歐幾里得演算法 需要解決這樣的問題:兩個非0整數a,b
擴充套件歐幾里得演算法(exgcd) 學習筆記
定義 首先引入一個叫做貝祖定理的東西 對於∀a,b∈N,總是∃x,y∈Z,使ax+by=(a,b) 已知a,b,求ax+by=(a,b)一組可行解的演算法即為擴充套件歐幾里得演算法。 演
擴充套件的歐幾里德演算法求乘法逆元
計算乘法逆元,比如3mod8的乘法逆元為3 是如何用歐幾里得演算法計算的呢??? 數對 x,y ,使得 gcd(a,b)=ax+by。 c++語言實現: #include <iostream&
歐幾里得演算法(求最大公因子)及擴充套件歐幾里得(求乘法逆元)
一、歐幾里得演算法歐幾里得演算法又稱輾轉相除法,是指用於計算兩個正整數a,b的最大公約數。gcd(a,b)=gcd(b,a mod b)。演算法描述:1. 輸入:兩個非負整數a,b,且a≥b。2. 輸出
51nod 1256 乘法逆元(擴充套件歐幾里得演算法)
思路1:把k*M%N=1可以寫成一個不定方程,(k*M)%N=(N*x+1)%N,那麼就是求k*M-N*x=1使得k最小,不定方程利用擴充套件歐幾里得演算法 --------------------------------------------------------
POJ-1061-青蛙的約會 (擴充套件歐幾里得演算法)
原題連結: http://poj.org/problem?id=1061 兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面為止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定
HDU-2669-Romantic (擴充套件歐幾里得演算法)
原題連結: http://acm.hdu.edu.cn/showproblem.php?pid=2669 The Sky is Sprite. The Birds is Fly in the Sky. The Wind is Wonderful. Blew Throw the Trees
POJ-2142-The Balance (擴充套件歐幾里得演算法)
原題連結: Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspiri
演算法學習(一)——歐幾里德演算法&擴充套件歐幾里得演算法
最大公約數/歐幾里德演算法(gcd) 歐幾里德演算法又稱輾轉相除法,證明可以度娘。 個人簡單腦部就是a和b兩個數的模還是a和b的最大公約數 int型別 int gcd(int a, int b) {return a%b==0?b:gcd(b,a%b);} long l
各種密碼學演算法的GUI程式設計實現(DES、AES、Present、擴充套件歐幾里得演算法、素性檢測)
encryption-algorithm 各種密碼學演算法的 C# GUI程式設計實現,包含: DES AES Present 擴充套件歐幾里得演算法 素性檢測 最終的結果 DES加密 DES解密
乘法逆元、擴充套件歐幾里得演算法、二元一次方程、a的n次方取餘
知識點:乘法逆元,逆元的求法,二元一次方程求通解,a的n次方求餘數 一,乘法逆元 乘法逆元的概念類似於倒數(ax=1,a−1=x),不過是在取餘數的情況下的倒數。 如果(a×x)%p=1,則稱x是a模p的逆元。另一種記法:ax=1(modp),即等
解的個數(直線上的點)(數論-擴充套件歐幾里得演算法)
Description 已知x,y滿足如下條件: ax+by+c=0 ; x1 <= x <= x2 ; y1 <= y <= y2 ; x,y均為整數。 其中:a,b,c,x1,x2,y1,y2 都是絕對值不超過 10^8 的整數。 求(x,
乘法逆元詳解【費馬小定理+擴充套件歐幾里得演算法】
乘法逆元 何為乘法逆元? 對於兩個數a,pa,p若gcd(a,p)=1gcd(a,p)=1則一定存在另一個數bb,使得ab≡1(modp)ab≡1(modp),並稱此時的bb為aa關於11模pp的乘法逆元。我們記此時的bb為inv(a)inv(a)或a−1a
POJ 2115 for求迴圈次數-數論-(同餘方程+擴充套件歐幾里得演算法)
題意:給定for迴圈的初始值,結束值和增量,還有一個模,求最少的迴圈次數。 分析: 讀完題後應該就知道是一個同餘的概念,所以就是解一個一元一次同餘方程,像上題一樣用擴充套件歐幾里得演算法。這題的trick點是k最大為32,那麼2^32超出了int,要用long long,所
青蛙的約會(擴充套件歐幾里得演算法+不定方程求解)
1.折磨了我好久,不過大概是懂了。 2.題目: 兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面