夜深人静写算法(三十六)- 中国剩余定理

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了夜深人静写算法(三十六)- 中国剩余定理相关的知识,希望对你有一定的参考价值。

📢博客主页:https://blog.csdn.net/WhereIsHeroFrom
📢欢迎各位 👍点赞 ⭐收藏 📝评论,如有错误请留言指正,非常感谢!
📢本文由 英雄哪里出来 原创,转载请注明出处,首发于 🙉 CSDN 🙉
作者的专栏:
  👉C语言基础专栏《光天化日学C语言》
  👉C语言基础配套试题《C试题100例》
  👉算法进阶专栏《夜深人静写算法》

一、前言

  当初学这个算法,纯粹是因为她叫 —— * * 剩余定理(那两个字发出来竟然被判定违规了,阿这……)。所以我们只能叫它的另一个名字 —— 孙子定理。有兴趣的朋友可以自行百度它原本的名字。

二、 物不知数

1、引例

【例题1】有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

  • 这个问题是中国南北朝时期的数学著作《孙子算经》卷下第二十六题,叫做 “物不知数” 问题,这个问题翻译成现代文的意思是:一个整数除以三余二,除以五余三,除以七余二,求这个整数。
  • 表示如下:
  • ( S ) : { x ≡ 2 ( m o d   3 ) x ≡ 3 ( m o d   5 ) x ≡ 2 ( m o d   7 ) (S): \\begin{cases}x \\equiv 2(mod \\ 3)\\\\ x \\equiv 3(mod \\ 5)\\\\ x \\equiv 2(mod \\ 7) \\end{cases} (S):x2(mod 3)x3(mod 5)x2(mod 7)
  • 由于每一行都是一个同余方程,其中 x x x 是公共的未知数。
  • 用这样的形式表示的我们称它为同余方程组, S S S 就是这个同余方程组。

三、同余方程组

  • 我们将同余方程表示成更加一般的形式,如下:
  • ( S ) : { x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) ⋮ x ≡ a n ( m o d   m n ) (S): \\begin{cases}x &\\equiv a_1(mod \\ m_1)\\\\ x &\\equiv a_2(mod \\ m_2)\\\\ &\\vdots \\\\ x &\\equiv a_n(mod \\ m_n) \\end{cases} (S):xxxa1(mod m1)a2(mod m2)an(mod mn)
  • 我们知道同余方程是可以表示成等式的形式的,那么同余方程组自然也可以,我们可以这么来表示:
  • ( S ) : { x = k 1 m 1 + a 1 x = k 2 m 2 + a 2 ⋮ x = k n m n + a n ( k i ∈ Z ) (S): \\begin{cases}x &= k_1m_1 + a_1\\\\ x &= k_2m_2 + a_2\\\\ &\\vdots \\\\ x &= k_nm_n + a_n\\end{cases} \\\\ \\\\ (k_i \\in Z) (S):xxx=k1m1+a1=k2m2+a2=knmn+an(kiZ)
  • n n n 个方程, n + 1 n+1 n+1 个未知数的情况下,解的情况可能存在,也可能不存在,存在的情只可能是无穷多解。

1、不存在解

  • 这种情况比较好理解,当存在 i i i j j j,同时满足 m i = m j m_i=m_j mi=mj a i ≠ a j a_i \\neq a_j ai=aj 时,解必然是不存在的。
  • 因为任何一个数模另外一个数,得到的结果一定是确定的,不可能有两种结果。

2、存在无穷多解

  • 一旦存在解,那么对于任意两个 i i i j j j,只要 m i = m j m_i=m_j mi=mj ,必然满足 a i = a j a_i = a_j ai=aj,出现这种情况时,变量数和方程数同时减少。
  • 换言之,未知数永远比方程数多 1,这样就一定有无穷多解了。

四、朴素算法

1、模数互素

  • 朴素算法就是穷举,以 “物不知数” 问题为例,我们可以从零开始枚举 x x x 的值。然后不断试除,看什么时候能够满足三个同余方程同时成立。
  • ( S ) : { x ≡ 2 ( m o d   3 ) x ≡ 3 ( m o d   5 ) x ≡ 2 ( m o d   7 ) (S): \\begin{cases}x \\equiv 2(mod \\ 3)\\\\ x \\equiv 3(mod \\ 5)\\\\ x \\equiv 2(mod \\ 7) \\end{cases} (S):x2(mod 3)x3(mod 5)x2(mod 7)
  • 代码实现如下:
#include <iostream>
using namespace std;

const int MAXN = 3;
int m[MAXN] = {3, 5, 7};
int a[MAXN] = {2, 3, 2};

int main() {
    for(int x = 0; x < 400; ++x) {      // (1)
        bool bfind = true;
        for(int i = 0; i < MAXN; ++i) { 
            if( x % m[i] != a[i] ) {    // (2)
                bfind = false;
                break;
            }
        }
        if(bfind) {
            printf("%d\\n", x);          // (3)
        }
    }	
    return 0;
}