POJ 1006 中国剩余定理

初见poj1006用的暴力破解写的代码,写完以后发现很搓。上网一查原来古人早就对此类问题有了解答规则。


一、中国剩余定理

一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:

有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。《孙子算经》中首次提到了同余方程组问题,以及以上具体问题的解法,因此在中文数学文献中也会将中国剩余定理称为孙子定理。

宋朝数学家秦九韶1247年数书九章》卷一、二《大衍类》对“物不知数”问题做出了完整系统的解答。明朝数学家程大位将解法编成易于上口的《孙子歌诀》:

三人同行七十希,五树梅花廿一支,七子团圆正半月,除百零五使得知

这个歌诀给出了模数为3、5、7时候的同余方程的秦九韶解法。意思是:将除以3得到的余数乘以70,将除以5得到的余数乘以21,将除以7得到的余数乘以15,全部加起来后除以105,得到的余数就是答案。比如说在以上的物不知数问题里面,使用以上的方法计算就得到

70 \times 2 + 21 \times 3 + 15 \times 2 = 233 = 2\times 105 +23.

因此按歌诀求出的结果就是23.

大致过程是:

n1*5*7%3=1,则n1最小为2;2*5*7=70.

n2*3*7%5=1,则n2最小为1;1*3*7=21.

n3*5*3%7=1,则n3最小为1;1*3*5=15.

n%3=2; 

n%5=3;

n%7=2;

所以n=(70*2+21*3+15*2)%(3*5*7)=233%105=23.


二、求解

有了上边的算法,求解poj1006就很简单啦。由题意我们很容易得到:

(n+d)%23=p;

(n+d)%28=e;

(n+d)%33=i;
并且,若a%b=c, k为正整数,则k*a%b=(k*c)%b

33*28%23=4,则6*33*28%23=4*6%23=1;  6*33*28=5544

23*33%28=3,则19*23*33%28=19*3%28=1;   19*23*33=14421

28*23%33=17,则2*28*23%33=2*17%33=1;  2*28*23=1288

23、28、33互质,最小公倍数23*28*33=21252

(5544*p+14421*e+1288*i)%21252=n+d


代码如下:

#include "stdafx.h"
#include<iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{	
	int p,e,i,d;
	cin>>p>>e>>i>>d;
	int num=0;
	int arr[10000][4];//用二维数组存储输入
	while(!(p==-1&&e==-1&&i==-1&&d==-1)){
		arr[num][0]=p;
		arr[num][1]=e;
		arr[num][2]=i;
		arr[num][3]=d;
		num++;//num记录输入数据的组数
		cin>>p>>e>>i>>d;

	}
	for(int i=0;i<num;i++){
		int j=(5544*arr[i][0]+14421*arr[i][1]+1288*arr[i][2])%21252-arr[i][3];
		if(j<=0)//防止出现输出0或者负数的情况
			j+=21252;
	  cout<<"Case "<<i+1<<": the next triple peak occurs in "<<j<<" days."<<endl;

	}
	return 0;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值