个人理解---中国剩余定理

 

              a1 r1    a2  r2     a3 r3 
有一个数x,除以3余2,除以5余3, 除以7余2,求x的最小值;
 
计算过程是:(70 * 2  + 21 *  3 + 15 * 2 ) % 105 = 23.
 
            (N1 * R1 + N2 * R2 + N3 * R3) % N   = x.
 
其中 70(N1)是5(A2)和7(A3)的最小公倍数,对3(A1)求余为1;
     21(N2)是3(A1)和7(A3)的最小公倍数,对5(A2)求余为1;
     15(N3)是3(A1)和7(A2)的最小公倍数,对5(A3)求余为1;
     N 为3(A1),5(A2),7(A3)的最小公倍数.
 
 
那么就可以推广到:
 
x % A1 = R1,
x % A2 = R2,
x % A3 = R3,
x % A4 = R4,
...... 
x % An = Rn.
求最小的x,其中Ai为素数;
 
N = A1 * A2 * A3 * A4 * ... * An;
 
所以我们要求出Ni, Ni=A1 * A2 *...* Ai-1 * Ai+1 *... * An * Ki,  根据Ni%Ai=1来确定Ki的值
 
x = (R1*N1 + R2*N2 + R3*N3 + ... + Rn*Nn)% N ;因为要求的是:最小整数解,所以对N求余即可;
 
 
下面关键就是求Ni,即求Ki;
因为N是所有A的乘积,Ni为除Ai外的所有Ai的倍数,所以:
Ni = N / Ai * K;(K为任意整数);---------式1;
又因为Ni对Ai求余为1,所以:
Ni = Ai * K0 + 1;(K0为任意整数);-------式2;
 
从上面可以看出只要我们求出K或者K0就可以求出Ni了;
 
由1,2式得N / Ai * K = Ai * K0 + 1
化简得:(N/Ai)*K + (-Ai)K0 = 1;
不难看出上式满足ax + by = gcd(a, b)
由上面的分析知道N/Ai与-Ai一定互质即gcd(N/Ai, -Ai) = gcd(N/Ai, Ai) = 1;
 
所以可以用扩展欧几里德来求解K和K0;
 

 

#include<stdio.h>

#define MAXN 22

int n, N0;

void ex_gcd(int a, int b, int &x, int &y)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return ;
    }
    ex_gcd(b, a%b, x, y);

    int temp = x;

    x = y;

    y = temp - a/b * y;

    if(a*b<0)///如果a和b异号那么x和y取反;理由不太清楚;
    {
        x = -x;
        y = -y;
    }
}

int China(int N[], int A[], int R[])
{
    int x = 0;

    for(int i=1; i<=n; i++)
    {
        int K, K0;

        ex_gcd(N0/A[i], -A[i], K, K0);

        N[i] = A[i] * K0 + 1; ///或者 N[i] = N0/A[i] * K;

        x = (x + N[i] * R[i] + N0) % N0;
    }
    return (x+N0)%N0;///防止出现负数;
}

int main()
{
    int A[MAXN], R[MAXN],  N[MAXN];

    scanf("%d", &n);

    N0 = 1;

    for(int i=1; i<=n; i++)
    {
        scanf("%d %d", &A[i], &R[i]);

        N0 *= A[i];
    }
    int x = China(N, A, R);

    printf("%d\n", x);

    return 0;
}

  

posted @ 2016-03-25 15:55  西瓜不懂柠檬的酸  Views(383)  Comments(0Edit  收藏  举报
levels of contents