1. 程式人生 > >擴展歐幾裏得算法詳解

擴展歐幾裏得算法詳解

rac int turn 發現 return 新解 求解 inline cda

本篇將附上擴展歐幾裏得算法的思想與推導;


對於一個方程\(a*x+b*y=gcd(a,b)\)來說,我們可以做如下的推導:

設有\(a*x_1+b*y_1=gcd(a,b)\);

同時我們有\(b*x_2+(a\%b)*y_2=gcd(b,a\%b)\);

對於這個方程組,我們希望知道的是\(x_1,x_2,y_1,y_2\)之間的關系,這樣我們才可以遞歸解決這個問題;

我們觀察\(b*x_2+(a%b)*y_2\)這個式子,我們可以將\((a\%b)\)寫作\((a-\lfloor\frac{a}{b}\rfloor*b)\),將括號打開常數\(a,b\)合並,合並之後的結果為\(a*y_2+b*(x_2-\lfloor\frac{a}{b}\rfloor*y_2))\)

由於歐幾裏得算法的原理\(gcd(a,b)==gcd(b,a%b)\),我們將兩式子聯立,對比系數即可得到\(x_1=y_2,y_1=x_2-\lfloor\frac{a}{b}\rfloor*y_2\);

這個遞歸的邊界是什麽呢?我們知道,當樸素歐幾裏得到達邊界時,\(return gcd(a,0)=a\),那麽邊界條件就是對\(a*x_0+b*y_0=a\)求解,很顯然,此時\(x_0=1,y_0=0\);

當我們遞歸求出了一個方程的特解時,如何求出這個方程的通解呢?

方程\(a*x+b*y=gcd(a,b)\)中,如果將x加上一個常數\(k_1,y\)減去一個常數\(k_2\),仍然保持原方程成立,那麽\(x+k_1,y-k-2\)
就是方程的一個新解,這個k應該如何選擇呢?

實際上很簡單,\(a*(x+k_1)+b*(y+k_2)=gcd(a,b)\),打開括號,\(a*x+a*k_1+b*y-b*k_2=gcd(a,b)\),我們保證原方程成立,就需要\(a*k_1==b*k_2\),那麽顯然\(k_1=b,k_2=a\)是一種合理的情況,但是這樣是無法包含所有整數解的,因為我們加上的這個值並非是最小值.

那我們應該加上什麽值才行呢?我們發現當\(a*k_1==b*k_2=t*lcm(a,b)\)可以保證得到所有解,於是每次尋找解就可以分別在\(x\)加上\(\frac{b}{gcd(a,b)},在y減去\frac{a}{gcd(a,b)}\)
就可以了

對於方程\(a*x+b*y=c\)我們又該如何求解?我們發現如果\((c%gcd(a,b)!=0)\)那麽這個方程是無解的,而如果\(gcd(a,b)*t==c\),我們就可以按上面的方法求解之後對我們的解乘上一個\(t(t=\frac{c}{gcd(a,b)})\)

\(code:\)


int exgcd(int a,int b,int &x1,int &y1)
{
    if(!b)
    {
        x1=1,y1=0;
        return a;
    }
    int x2,y2;
    int d=exgcd(b,a%b,x2,y2);
    x1=y2,y1=x2-(a/b)*y2;
    return d;
}

擴展歐幾裏得算法詳解