中國剩餘定理

來源:互聯網
上載者:User

標籤:中國剩餘定理   同於方程組   數論   韓信點兵   孫子定理   

中國剩餘定理介紹

在《孫子算經》中有這樣一個問題:“今有物不知其數,三三數之剩二(除以3餘2),五五數之剩三(除以5餘3),七七數之剩二(除以7餘2),問物幾何?”這個問題稱為“孫子問題”,

明朝數學家程大位在他著的《演算法統宗》(1593年)中就用四句很通俗的口訣暗示了此題的解法:  

三人同行七十稀,   

五樹梅花甘一枝,   

七子團圓正半月,   

除百零五便得知。  

 "正半月"暗指15。"除百零五"的原意是,當所得的數比105大時,就不斷減105,直到使之小於105;這相當於用105去除,求出餘數。用數學的方式表達就是(70*3+21*5+15*7)%105=23

該問題的一般解法在國際上稱為“中國剩餘定理”。具體解法可以分為三步:

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的餘數);

把三個乘積相加(15*2+21*3+70*2)得到和233。

3. 求合格最小數:

用三個乘積的和233除以3,5,7三個數的最小公倍數105,得到餘數23,即233%5=23。這個餘數23就是合格最小數。

中國剩餘定理分析(兩兩互質)

我們可以將“孫子問題”分解成幾個簡單的小問題。

首先,我們假設n1是滿足除以3餘2的一個數,比如2,5,8等等。同樣,我們假設n2是滿足除以5餘3的一個數,n3是滿足除以7餘2的一個數。

有了這些假設,我們先從n1角度分析,已知n1滿足除以3餘2,能不能使得 n1+n2 的和仍然滿足除以3餘2呢?進而使得n1+n2+n3的和仍然滿足除以3餘2呢?

這裡涉及到一個基本的數學定理,如果有a%b=c,則有(a+kb)%b=c(k為非零整數),通俗地講,如果一個除法運算的餘數為c,那麼被除數與k倍的除數相加(或相減)的和(差)再與除數相除,餘數不變。

根據這個定理,如果n2是3的倍數,n1+n2就依然滿足除以3餘2。同理,如果n3也是3的倍數,那麼n1+n2+n3的和就滿足除以3餘2。這是從n1的角度考慮的,再從n2,n3的角度分析,我們可推匯出以下三點:

1. 為使n1+n2+n3的和滿足除以3餘2,n2和n3必須是3的倍數。

2. 為使n1+n2+n3的和滿足除以5餘3,n1和n3必須是5的倍數。

3. 為使n1+n2+n3的和滿足除以7餘2,n1和n2必須是7的倍數。

因此,為使n1+n2+n3的和作為“孫子問題”的一個最終解,需滿足:

1. n1除以3餘2,且是5和7的公倍數。

2. n2除以5餘3,且是3和7的公倍數。

3. n3除以7餘2,且是3和5的公倍數。

所以,孫子問題解法的本質是從5和7的公倍數中找一個除以3餘2的數n1,從3和7的公倍數中找一個除以5餘3的數n2,從3和5的公倍數中找一個除以7 餘2的數n3,再將三個數相加得到解。(在求n1,n2,n3時有一個小技巧,以n1為例,並非從5和7的公倍數中直接找一個除以3餘2的數,而是先找一個除以3餘1的數,再乘以2。)

這裡又有一個數學公式,如果a%b=c,那麼(a*k)%b=a%b+a%b+…+a%b=c+c+…+c=kc(k>0),也就是說,如果一個除法的餘數為c,那麼被除數的k倍與除數相除的餘數為kc。如展開式中的證明。

最後,我們還要注意,n1+n2+n3隻是問題的一個解,並不是最小的解。如何得到最小解?我們只需要從中最大限度的減掉掉3,5,7的公倍數105 即可。道理就是前面講過的定理“如果a%b=c,則有(a-kb)%b=c”。所以(n1+n2+n3)%105就是最終的最小解。



以上只是對求孫子問題的簡單分析過程,那麼如果給出的不僅僅是三組呢?而是10組,20組或者更多呢?下面我們就中國剩餘定理進行深入分析,探尋一種解法。

設有n組資料,每組資料的除數為P[i],餘數為R[i](1<=i<=n),根據上面對孫子問題的分析,我們知道,首先我們要在P[2],P[3],……,P[n]的公倍數中找到一個除以P[1]餘R[1]的數num[1],在P[1],P[3],……,P[n]的公倍數中找到一個除以P[2]餘R[2]的數num[2],……,在P[1],P[2],……,P[n-1]的公倍數中找到一個除以P[n]餘R[n]的數num[n],然後將num[1],num[2],num[3],……,num[n]累加求和sum,最後用sum對P[1],P[2],……,P[n]的最小公倍數求餘,得到的數即是合格最小整數。

注意:孫子問題分析時是求出所有數的和在取餘,當組數少時,這是沒問題的,但是當組數太多時和必然也多,這裡我們可以利用公式(a+b)%c=(a%c+b%c)%c就可將程式最佳化

程式演算法的解法代碼:

代碼如下:

可運行代碼:C/C++代碼

#include<stdio.h>#include <iostream>using namespace std;//擴充歐幾裡得演算法int exgcd(int a,int b,int &x,int &y){    int d;    if(b==0)    {        x=1;y=0;        return a;    }    d=exgcd(b,a%b,y,x);    y-=a/b*x;    return d;} //中國剩餘定理 ,r[]存放餘數 ,prime[]存放兩兩互質的數int Chinese_Remainder(int r[],int prime[],int len){    int i,d,x,y,m,n=1,sum=0;    //計算所以除數的積n,也是所以除數的最小公倍數    for(i=0;i<len;i++)        n*=prime[i];    //計算符合所以條件的數    for(i=0;i<len;i++)    {        m=n/prime[i];//計算除去本身的所以除數的積m        d=exgcd(prime[i],m,x,y);//計算w[i]*x+m*y=gcd(w[i],m)的一個解y        //累加整數解y的同並不斷對n取餘,其利用公式:(a+b)%c=(a%c+b%c)%c        sum=(sum+y*m*r[i])%n;    }    return (n+sum%n)%n;//滿足所以方程的最小解}int main(){    int n,i;    int prime[15],r[15];    while (printf("請輸入組數n:\n"),scanf("%d",&n)!=EOF)    {        printf("請依次輸入每組的除數和餘數:\n");        for (i=0;i<n;i++)        {            scanf("%d%d",&prime[i],&r[i]);        }        //printf("%d\n",Chinese_Remainder(b,w,n));        printf("合格最小整數:%d\n\n",Chinese_Remainder(r,prime,n));    }    return 0;}

核心代碼:

int Chinese_Remainder(int r[],int prime[],int len){    int i,d,x,y,m,n=1,sum=0;    for(i=0;i<len;i++)        n*=prime[i];    for(i=0;i<len;i++)    {        m=n/prime[i];        d=exgcd(prime[i],m,x,y);        sum=(sum+y*m*r[i])%n;    }    return (n+sum%n)%n;}





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.