中国剩余定理

一、同余的概念

所谓的同余,顾名思义,就是许多的数被一个数d去除,有相同的余数。d在数学上的称谓是模。如a=6,b=1,d=5,则我们说a和b是模d同余的。因为他们都有相同的余数1。数学上的记法为:a ≡ b (mod d)。也就是说,a除以d所得之余数与b除以d所得之余数是相等的,例如6  1 (mod 5)。

同余有一些非常重要的性质,例如:

(1)如果a≡x (mod d),b≡m(mod d),则有 a+b≡x+m (mod d)

(2)如果a≡x (mod d),b≡m(mod d),则有 a – b≡x-m (mod d)。

(3)如果a≡x (mod d),b≡m(mod d),则有 a * b≡x*m(mod d)。

(4)如果a≡b (mod d)则a-b整除d

二、中国剩余定理


《孙子算经》中,有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”按照今天的话来说:一个数除以3余2,除以5余3,除以7余2,求这个数。这样的问题,也有人称为“韩信点兵”。它形成了一类问题,也就是初等数论中的解同余式。宋朝数学家秦九韶在其所著的《数书九章》中对“物不知数”问题做出了完整系统的解答。后来这个结论被称为中国剩余定理。


用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:

《中国剩余定理》

有解的判定条件,并用构造法给出了在有解情况下解的具体形式。

《中国剩余定理》


三、一个例子


《中国剩余定理》


四、编程实现


分析:M=m1 * m2 *… * mk,L, J为任意整数。因为Mi能被m1, m2,…,mi-1, mi+1,…,mk整除(其中i+1<k),因此: Mi = (M/mi) *L
又因为Mi除以mi余1,所以: Mi = mi*J + 1。即: mi*J + 1 = (M/mi)*L => (-mi)*J + (M/mi)*L = 1
而m1到mk这些数都是互质数,所以(-mi) 同 (M/mi)也是互质数.即 gcd(-mi, M/mi) = 1。

也就是说:(M/mi)*L + (-mi)*J  = gcd(M/mi, -mi) => 其中-mi和M/mi都是已知的,J和L未知。
这就是经典扩展欧几里德定理的原型(由定理知J和L是唯一的, 因此,M1–>Mk有唯一解),按照扩展欧几里德定理求解即可:

《中国剩余定理》

扩展欧几里得函数实现如下:

void extend_Euclid(int a, int b, int &x, int &y){
    //根据欧几里德定理
    if(b == 0){//任意数与0的最大公约数为其本身。
        x = 1;
        y = 0;
    }else{
        int x1, y1;
        extend_Euclid(b, a%b, x1, y1);
        if(a*b < 0){//异号取反
            x = - y1;
            y = a/b*y1 - x1;
        }else{//同号
            x = y1;
            y = x1 - a/b* y1;
        }
    }
}

最后完成的中国剩余定理实现函数如下:

int CRT(int a[],int m[],int k)
{
    int M = 1;//最小公倍数
    int result = 0;
    for(int i = 0; i < k; i++){
        M *= m[i];
    }
    
    for(int j = 0; j < k; j++){
        int L, J;
        extend_Euclid(M/m[j], -m[j], L, J);
        
        //Mi = m[j] * J + 1;//(1), (1)和(2)这两个值应该是相等的。
        int Mi = M/m[j] * L;//(2)
        result += Mi*a[j];
    }
    
    //落在(0, M)之间,这么写是为了防止result初始为负数,确定不可能为负时可直接写成return result%M;

    return (result % M + M) % M;

}

最后给一个测试用main函数:

int main(int argc, const char * argv[]) {
    
    int a[3] = {2, 3, 2};
    int m[3] = {3, 5, 7};
    
    printf("Result: %d\n", CRT(a, m, 3));
    return 0;
}


(本文完)

    原文作者:算法
    原文地址: https://blog.csdn.net/baimafujinji/article/details/6472129
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞