歐幾里得與擴展歐幾里得

歐幾里得:

int gcd(int a, int b)
{
    return !b ? a : gcd(b, a%b);
}
int lcm(int a, int b)//最小公倍數
{
    return a / gcd(a, b) * b;//先除後乘避免溢出
}

擴展歐幾里得:

存在整數對(x,y) 使得ax+by=gcd(a,b)
推導過程:
用遞歸求解擴展歐幾里得,設已經求出了下一層遞歸的解,即:ax1+by1=gcd(a,b)(x1,y1)
a%b=a(a/b)b
(x1,y1) 代入到bx1+(a%b)y1=gcd(a,b) 中,得
bx1+(a(a/b)b)y1=gcd(a,b) => ay1+b(x1(a/b)y1)=gcd(a,b)
b=0 時,顯然有a1+b0=gcd(a,b)
寫成代碼,模板如下

int extgcd(int a, int b, int &x, int &y)
{
    int d = a;
    if(b != 0)
    {
        d = extgcd(b, a%b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}

求解不定方程:

c%gcd(a,b)=0 ,則存在整數對(x,y) ,使得ax+by=c
通過上面的方法可得到一組特解(x0,y0) 使得ax+by=gcd(a,b) ,那麼如何在無窮多個解中求出xy 最小正整數解。

證明:

首先 ax0+akb/gcd(a,b)+by0akb/gcd(a,b)=gcd(a,b)
a(x0+kb/gcd(a,b))+b(y0ka/gcd(a,b))=gcd(a,b)
通解爲x=x0+kb/gcd(a,b)y=y0ka/gcd(a,b) ,其中k=...2,1,0,1,2...
在所有解中最小的正整數爲(x0+b/gcd(a,b))
所以對於方程ax+by=c ,最小正整數解(以x 爲例)爲(x0c/gcd(a,b)+b/gcd(a,b))
注意:若b 爲負數,需將b 轉換爲正數。

int cal(int a, int b, int c)
{
    int x, y;
    int gcd = extgcd(a, b, x, y);
    if(c % gcd != 0) return -1;
    x *= c/gcd;
    b /= gcd;
    if(b < 0) b = -b;
    int ans = x % b;
    if(ans <= 0) ans += b;
    return ans;
}

同餘方程:

根據上面的內容,我們可以得到:

axb(mod n) ,轉化爲ax+ny=b ,當b 時,方程有 gcd(a,n) 個解。
ax1(mod n) ,如果gcd(a,n)=1 ,則方程有唯一解。

解線性方程ax+by=c

bool cal(int a, int b, int c)
{
    int x0, y0;
    int d = extgcd(a, b, x0, y0);
    if(c % d) return false;
    int x = x0*c/d, y = y0*c/d;
    kx = b/d, ky = -a/d;
    return true; // 解集爲:(x+kx*t, y+ky*t),t爲整數
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章