1. 程式人生 > >[搬運]關於擴充套件歐幾里得與同餘方程

[搬運]關於擴充套件歐幾里得與同餘方程

什麼是GCD?

GCD是最大公約數的簡稱(當然理解為我們偉大的黨也未嘗不可)。在開頭,我們先下幾個定義:
①a|b表示a能整除b(a是b的約數)
②a mod b表示a-[a/b]b([a/b]在Pascal中相當於a div b)
③gcd(a,b)表示a和b的最大公約數
④a和b的線性組合表示ax+by(x,y為整數)。我們有:若d|a且d|b,則d|ax+by(這很重要!)

線性組合與GCD
現在我們證明一個重要的定理:gcd(a,b)是a和b的最小的正線性組合。
證明:
設gcd(a,b)為d,a和b的最小的正線性組合為s
∵d|a且d|b,
∴d|s。
而a mod s=a-[a/s]s
=a-[a/s](ax+by)
=a(1-[a/s]x)-b[a/s]y
亦為a和b的線性組合
∵a mod s<s,a mod s不能是a和b的最小的正線性組合
∴a mod s=0,即s|a
同理由s|b
∴s為a,b的公約數
∴s<=d
∵d|s
∴d=s。證畢。

由這條定理易推知:若d|a且d|b,則d|gcd(a,b)

擴充套件歐幾里得是對於一對整數a,b總可以找到一組解x,y使ax+by=gcd(a,b)

例如a=6,b=15時,gcd(a,b)=3;一組可行的解是x=3,y=-1,當然還有其他解如x=-2,y=1.

給出實現程式

int exGcd(int a,int b,int &d,int &x,int &y)//d表示gcd(a,b)
{
    if(!b){d=a; x=1; y=0;}
    else {exGcd(b,a%b,d,y,x); y-=x*(a/b);}
}


我們說過,gcd(a,b)可以表示為a和b的最小的正線性組合。現在我們就要求這個最小的正線性組合ax+by中的x和y。

從最簡單的情況開始。當b=0時,我們取x=1,y=0。當b≠0時呢?
假設gcd(a,b)=d,則gcd(b,a mod b)=d。若我們已經求出了gcd(b,a mod b)的線性組合表示bx’+(a mod b)y’,則
gcd(a,b)=d
=bx’+(a mod b)y’
=bx’+(a-[a/b]b)y’

=ay’+b(x’-[a/b]y’)=d=ax+by

那麼,x=y’,y=x’-[a/b]y’。這樣就可以在Euclid的遞迴過程中求出x和y。

所以在上述程式碼的第4行中:

x=y’;(即x與y交換)

(交換前)y=x’-(a/b)*y’;

(交換後)y=y’-(a/b)*x’;

所以遞迴時

exGcd(b,a%b,d,y,x);交換了x,y
y-=x*(a/b);//更新了y

求出了一組解肯定遠遠不夠,如何求出其他解呢?一個公式就可以解決,對於方程的一個解(x0,y0)它的任意整數解可以表示為

  x = x0 + k*b/gcd(a, b)

       y = y0 – k*a/gcd(a, b)

其中k = 1, 2, … ,gcd(a, b)

同餘方程:aΞb(mod n)表示(a mod n)==(b mod n)即a-b可以被n整除(注意是整除);

所以可以設ax-b為n的正整數倍,所以又可以設ax-b為n的y倍;

得到ax-b==ny變形得ax-ny==b;

這下就可以用擴充套件歐幾里得解決了!