您的位置:首页 > 其它

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

2016-03-25 15:55 246 查看
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;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: