zoukankan      html  css  js  c++  java
  • 中国剩余定理(CRT)

    背景


     在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以$3$余$2$),五五数之剩三(除以$5$余$3$),七七数之剩二(除以$7$余$2$),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。具体解法分三步:

    1. 找出三个数:从$3$和$5$的公倍数中找出被$7$除余$1$的最小数$15$,从$3$和$7$的公倍数中找出被$5$除余$1$ 的最小数$21$,最后从$5$和$7$的公倍数中找出除$3$余$1$的最小数$70$。
    2. 用$15$乘以$2$($2$为最终结果除以$7$的余数),用$21$乘以$3$($3$为最终结果除以$5$的余数),同理,用$70$乘以$2$($2$为最终结果除以$3$的余数),然后把三个乘积相加$(15ast 2+21ast 3+70ast 2)$得到和$233$。
    3. 用$233$除以$3,5,7$三个数的最小公倍数$105$,得到余数$23$,即$233\%105=23$。这个余数$23$就是符合条件的最小数。

    就这么简单。我们在感叹神奇的同时不禁想知道古人是如何想到这个方法的,有什么基本的数学依据吗?

    分析


     我们将“孙子问题”拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出这个解法的。

      首先,我们假设$n_{1}$是满足除以$3$余$2$的一个数,比如$2$,$5$,$8$等等,也就是满足$3ast k+2$$(kgeq 0)$的一个任意数。同样,我们假设$n_{2}$是满足除以$5$余$3$的一个数,$n_{3}$是满足除以$7$余$2$的一个数。

      有了前面的假设,我们先从$n_{1}$这个角度出发,已知$n_{1}$满足除以$3$余$2$,能不能使得 $n_{1}+n_{2}$ 的和仍然满足除以$3$余$2$?进而使得$n_{1}+n_{2}+n_{3}$的和仍然满足除以$3$余$2$?

      这就牵涉到一个最基本数学定理,如果有$a\%b=c$,则有$(a+kast b)\%b=c$($k$为非零整数),换句话说,如果一个除法运算的余数为$c$,那么被除数与$k$倍的除数相加(或相减)的和(差)再与除数相除,余数不变。这个是很好证明的。

      以此定理为依据,如果$n_{2}$是$3$的倍数,$n_{1}+n_{2}$就依然满足除以$3$余$2$。同理,如果$n_{3}$也是$3$的倍数,那么$n_{1}+n_{2}+n_{3}$的和就满足除以$3$余$2$。这是从$n_{1}$的角度考虑的,再从$n_{2}$,$n_{3}$的角度出发,我们可推导出以下三点:

        1. 为使$n_{1}+n_{2}+n_{3}$的和满足除以$3$余$2$,$n_{2}$和$n_{3}$必须是$3$的倍数。
        2. 为使$n_{1}+n_{2}+n_{3}$的和满足除以$5$余$3$,$n_{1}$和$n_{3}$必须是$5$的倍数。
        3. 为使$n_{1}+n_{2}+n_{3}$的和满足除以$7$余$2$,$n_{1}$和$n_{2}$必须是$7$的倍数。

      因此,为使$n_{1}+n_{2}+n_{3}$的和作为“孙子问题”的一个最终解,需满足:

        1. $n_{1}$除以$3$余$2$,且是$5$和$7$的公倍数。
        2. $n_{2}$除以$5$余$3$,且是$3$和$7$的公倍数。
        3. $n_{3}$除以$7$余$2$,且是$3$和$5$的公倍数。

      所以,孙子问题解法的本质是从$5$和$7$的公倍数中找一个除以$3$余$2$的数$n_{1}$,从$3$和$7$的公倍数中找一个除以$5$余$3$的数$n_{2}$,从$3$和$5$的公倍数中找一个除以$7$余$2$的数$n_{3}$,再将三个数相加得到解。在求$n_{1}$,$n_{2}$,$n_{3}$时又用了一个小技巧,以$n_{1}$为例,并非从$5$和$7$的公倍数中直接找一个除以$3$余$2$的数,而是先找一个除以$3$余$1$的数,再乘以$2$。

      这里又有一个数学公式,如果$a\%b=c$,那么$(aast k)\%b=a\%b+a\%b+…+a\%b=c+c+…+c=kast c$  ($k>0$),也就是说,如果一个除法的余数为$c$,那么被除数的$k$倍与除数相除的余数为$kast c$。展开式中已证明。

      最后,我们还要清楚一点,$n_{1}+n_{2}+n_{3}$只是问题的一个解,并不是最小的解。如何得到最小解?我们只需要从中最大限度的减掉掉$3$,$5$,$7$的公倍数$105$即可。道理就是前面讲过的定理“如果$a\%b=c$,则有$(a-kast b)\%b=c$”。所以$(n_{1}+n_{2}+n_{3})\%105$就是最终的最小解。

    解法


    设正整数$m_{1},m_{2}cdots m_{k}$两两互素,则同余方程组

    $xequiv a_{1}(mod$ $m_{1})$
    $xequiv a_{2}(mod$ $m_{2})$
    $xequiv a_{3}(mod$ $m_{3})$
        $vdots $
    $xequiv a_{k}(mod$ $m_{k})$

     有整数解。并且在模$M=m_{1}cdot m_{2} cdots m_{k}$下的解是唯一的,解为

                                  $xequiv (a_{1}M_{1}M_{1}^{-1}+a_{2}M_{2}M_{2}^{-1}+a_{k}M_{k}M_{k}^{-1})mod$ $M$

    其中$M_{i}=M/m_{i}$,而$M_{1}^{-1}$为$M_{i}$模$m_{i}$的逆元。

    Code

    int CRT(int a[],int m[],int n) {
        int M = 1, ans = 0;
        for(int i = 1; i <= n; i++) M *= m[i];
        for(int i = 1; i <= n; i++) {
            int x, y;
            int Mi = M/m[i];
            exgcd(Mi, m[i], x, y);
            ans = (ans+Mi*x*a[i])%M;
        }
        if(ans<0) ans += M;
        return ans;
    }
    View Code

    参考文章:
    https://www.cnblogs.com/walker01/archive/2010/01/23/1654880.html

    https://blog.csdn.net/acdreamers/article/details/8050018

  • 相关阅读:
    2013-8-14大一大二暑期组队训练赛
    注重实效的程序员——哲学篇
    读《企业应用架构模式》-锁
    OpenCV 编码样式指南
    Offer_1
    μC/OS学习资料(附Ebook)
    poj 1990
    POJ 2455 网络流 基础题 二分+网络流 dicnic 以及 sap算法
    ViewPageAsImage
    win7下wordPress本地搭建博客详解(深度亲测整理---傻瓜式详细教程)
  • 原文地址:https://www.cnblogs.com/wizarderror/p/11432052.html
Copyright © 2011-2022 走看看