中國剩餘定理與線性同餘方程組求解

線性同餘方程組的形式

實際上一元一次線性同餘方程組,形式如下:

{xr0(modm0)xr1(modm1)

包含有具體數字的線性同餘方程組問題最早見於《孫子算經》(成書於約南北朝時期,因此與《孫子兵法》的孫子應該不是同一個孫子),該書也給出了該具體問題的解法。因此求解線性同餘方程組有關的定理又稱作孫子定理。但實際上《孫子算經》並未給出證明及一般性解法。最早的系統性論述應該是南宋時期秦九韶在《算術九章》中提出的“大衍求一術”。因此最後有關該問題的理論被稱作中國剩餘定理。

中國剩餘定理

如果m0,m1, 兩兩互質,則方程有唯一解,在模imi 的意義下。解法如下:
M=imi ,且Mi=M/mi
對每一個Mi 求出在模mi 意義下的逆元,記作xi
即滿足Mixi1(modmi)
則原方程組的解爲x=irixiMimodM

線性同餘方程組的一般解法

使用中國剩餘定理理論上可以很方便的解出模數兩兩互質的方程組。對於不互質的情況可以使用下面的一般解法。

單獨的線性同餘方程求解

考慮單獨的一個線性同餘方程,已知a,b,m ,求x 滿足如下方程:

axb(modm)

原方程等價於:
ax+my=b

根據裴蜀定理,上述方程有解的充要條件是bgcd(a,m) 的整數倍。利用擴展的擴展的歐幾里德算法可以很容易求得x0 使得:
ax0+my0=gcd(a,m)

於是很容易得到x 的一個特解爲:
x=x0bgcd

顯然x 有無窮多解,如果考慮在模m 的意義下,x 也有gcd 個不同的解,且成等差數列,公差爲m/gcd 。因此很容易求得最小正整數解爲:
x=x0bgcdmodmgcd

考慮方程
9x6(mod12)

根據擴展的歐幾里德算法有:
9x0+12y0=3

得到x0 的一個解爲11,所以x 的一個解爲22,對4取模即可得到最小正整數解2,且在模12的意義下有3個解,分別是2、6、10。

兩個線性同餘方程合併

考慮2個線性同餘方程構成的方程組:

{xr0(modm0)xr1(modm1)

分別等價於
{x=r0+m0z0x=r1+m1z1

因此有
m0z0=m1z1+r1r0

兩邊對m2 取餘數即可得到一個單獨的關於z0 線性同餘方程
m0z0r1r0(modm1)

根據之前的結論,很容易判斷是否有解並可以解出z0 。如果可解,可以得到一個方程:
xm0z0+r0(modlcm(m0,m1))

該方程與原方程組等價。其中lcm 爲最小公倍數。
如此反覆,就可以將線性同餘方程組合併爲一個方程,並且利用擴展的歐幾里德算法求解。在每一步中,均需判斷是否有解。
typedef long long int llt;
//to convert two congruence equations to equivalent one
//x = r1 (mod m1)
//x = r2 (mod m2)
//the out put is:  x = r3 (mod m3)
//return true if there is a solution, otherwise false
bool mergeCrt(llt r1,llt m1,llt r2,llt m2,llt&r3,llt&m3){
    llt x,y;
    llt g = exEuclid(m1,m2,x,y);
    llt r = (r2 - r1) % m2;
    if ( r < 0 ) r += m2;

    if ( r % g ) return false;//no solution

    x = r / g * x % ( m2 / g );//the least positive solution

    m3 = m1 / g * m2; //lcm
    r3 = ( ( x * m1 ) % m3 + r1 ) % m3;
    return true;
}

//Chinese remainder theorem to solve linear congruence equations
//n is the count of equations
//remainder is the array of remainders, index from 0
//mod is the array of modules, index from 0
//return the least positive solution or -1 if there is no solution
llt Crt(int n,llt const remainder[],llt const mod[]){
    llt r1 = remainder[0],m1 = mod[0];
    for(int i=1;i<n;++i){
        if ( !mergeCrt(r1,m1,remainder[i],mod[i],r1,m1) ){
            return -1;
        }
    }

    r1 %= m1;
    if ( r1 < 0 ) r1 += m1;
    return r1;
}

完整的程序可以見POJ2891

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章