您的位置:首页 > 其它

POJ1006 Biorhythms(生理周期,中国剩余定理详述)

2015-11-16 08:56 591 查看
Description
  人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因为三个周期的周长不同,所以通常三个周期的高峰不会落在同一天。对于每个人,我们想知道何时三个高峰落在同一天。对于每个周期,我们会给出从当前年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。你的任务是给定一个从当年第一天开始数的天数,输出从给定时间开始(不包括给定时间)下一次三个高峰落在同一天的时间(距给定时间的天数)。例如:给定时间为10,下次出现三个高峰同天的时间是12,则输出2(注意这里不是3)。
Input
  输入四个整数:p, e, i和d。 p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d 是给定的时间,可能小于p, e, 或 i。 所有给定时间是非负的并且小于365, 所求的时间小于21252。 

  当p = e = i = d = -1时,输入数据结束。
Output
  从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。 

采用以下格式: 

Case 1: the next triple peak occurs in 1234 days. 

  注意:即使结果是1天,也使用复数形式“days”。
Sample Input
0 0 0 0
0 0 0 100
5 20 34 325
4 5 6 7
283 102 23 320
203 301 203 40
-1 -1 -1 -1

Sample Output
Case 1: the next triple peak occurs in 21252 days.
Case 2: the next triple peak occurs in 21152 days.
Case 3: the next triple peak occurs in 19575 days.
Case 4: the next triple peak occurs in 16994 days.
Case 5: the next triple peak occurs in 8910 days.
Case 6: the next triple peak occurs in 10789 days.

题目:http://poj.org/problem?id=1006

这一题是中国剩余定理,中国剩余定理概念及相关:

http://baike.baidu.com/link?url=oX4jZ9SCVu5lKDwFJQx-Lhwga1KimUyukk3VIAwUoRpK5gY9BTmM0UePXtYBgauGZf_-GLrG6xX5-peyQsnEJwOfnm6OSmB2mVLxbKrrStoop64cirabbXTomITKDUdLVgS4mJj-1iprpvQ8Qcnjpicyt3wxhc_cfMCGakFFopw_NvRy72TG7KRaRdFq6UWbGpEYR3ggWWhWcImUjMNZc_

http://blog.sina.com.cn/s/blog_a6f9a3b60101favb.html

感谢博主。

首先看一下下面的题目,方便引出有关中国剩余定理的解法:

题目:今有物不知其数,三三数之剩二;五五数之剩三;七七数之剩二。问物几何?

解法:凡三三数之剩一,则置七十;五五数之剩一,则置二十一;七七数之剩十五;一百六以上,以一百零五减之即得;

上面计算方法可以写成如下式子:

       70*2+21*3+15*2=233

       233-105*2=23

初看解法时真是一头雾水,为什么“则置七十”,“则置二十一”,“则置十五”,解法中并没有说明,而且上网找了很多资料,并没有找到原因,但欣慰的一点是找到了怎么可以算出来这里的“七十”,“二十一”,“十五”,上面的解法中也提到了,不过开始看时不太理解;下面是算法:

下面是对上面题目的详细算法,也是这一类题的通用解法:

这类题就是解一元一次同余式方程组,即已知三个式子中的除数分别为y1,y2,y3, 余数分别为z1,z2,z3,他们的被除数相同,为x,求x。可以写成下面的式子:

x=z1 (mod y1);                         x÷y1=Z1...z1;

x=z2 (mod y2);   也可以写成    x÷y2=Z2...z2;

x=z3 (mod y3);                         x÷y3=Z3...z3;

对于上面的题目可以写成:

x=2 (mod 3);                         x÷3=Z1...2;

x=3 (mod 5);    也可以写成   x÷5=Z2...3;

x=2 (mod 7);                         x÷7=Z3...2;

1)求出“七十”,“二十一”,“十五”的方法;

i:

for(i=0;;i++)
{//这里既是解得上面的“则置七十”,但不知道为什么
if(5*7*i%3==1)
{
a=5*7*i;
break;
}
}

运算后a为70,这里3作为除数,求出直到满足5*7*i%3==1的i为止,则a=5*7*i;

ii:

for(i=0;;i++)
{//这里既是解得上面的“则置二十一”,但不知道为什么
if(3*7*i%5==1)
{
b=3*7*i;
break;
}
}

运算后b为21,这里5作为除数,求出直到满足3*7*i%5==1的i为止,则b=3*7*i;

iii:

for(i=0;;i++)
{//这里既是解得上面的“则置十五”,但不知道为什么
if(3*5*i%7==1)
{
c=3*5*i;
break;
}
}

运算后c为15,这里7作为除数,求出直到满足3*5*i%7==1的i为止,则c=3*5*i;

2)求出余数的最小公倍数;

一般给出的数字不会很大,手算就能算出来,这里给出一种方法:

int Lcm(int i,int j)
{
int a=i,b=j,n;
if(i<j)
{int t=i;i=j;j=t;}
do
{
n=i%j;
i=j;
j=n;
}
while(n>0);
return a*b/i;
}

则3,5,7的最小公倍数即为Lcm(Lcm(3.5.7));

3)求被除数x

x=(a*2+b*3+c*2)%Lcm(3.5.7)

其中2,3,2分别是余数,Lcm(3.5.7)是3,5,7的最小公倍数。

上面这一题代码:

//中国剩余定理得计算方法实验
//------------------------------问题如下-------------------------------//
//“中国剩余定理”是公元5-6世纪、我国南北朝时期的一部著名算术著作《孙子算经》 //
//中的一个“物不知数”的解法问题:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。 //
//问物几何?答曰:二十三。 //
//-------------------------------------------------------------------//
//----------------------------古人的解法-------------------------------//
//凡三三数之剩一,则置七十;五五数之剩一,则置二十一;七七数之剩一则置十五;一百六以上, //
//以一百零五减之即得。 //
// 依定理译成算式解为: //
// 70×2+21×3+15×2=233 //
// 233-105×2=23 //
//-------------------------------------------------------------------//

import java.util.Scanner;
public class Poj1006_Test {
public static void main(String[] agrs)
{
Scanner input=new Scanner(System.in);
int a,b,c,i;
for(i=0;;i++)
{//这里既是解得上面的“则置十五”,但不知道为什么
if(3*5*i%7==1)
{
a=3*5*i;
break;
}
}
for(i=0;;i++) {//这里既是解得上面的“则置二十一”,但不知道为什么 if(3*7*i%5==1) { b=3*7*i; break; } }
for(i=0;;i++)
{//这里既是解得上面的“则置七十”,但不知道为什么
if(5*7*i%3==1)
{
c=5*7*i;
break;
}
}
System.out.printf("%d %d %d %d\n",a,b,c,(a*2+b*3+c*2)%(3*5*7));
//解得a,b,c后按照上面的式子就能解出结果
input.close();
}

}


POJ1006代码如下:

//:Poj1006 Biorhythms
//此题目写成数学表达式即为:(n+d)%23=p;(n+d)%28=e;(n+d)%28=i. 即已知除数和余数,求被除数n+d.
import java.util.Scanner;
public class Poj1006 {

int Lcm2(int i,int j)
{
int a=i,b=j,n;
if(i<j)
{int t=i;i=j;j=t;}
do
{
n=i%j;
i=j;
j=n;
}
while(n>0);
return a*b/i;
}
int Lcm3(int a,int b,int c)
{
return Lcm2(Lcm2(a,b),c);
}

public static void main(String[] agrs)
{
int Physical=23,Emotional=28,Intellectual=33;//各个周期
int r, a,b,c;
for(r=0;;r++)
if(Physical*Emotional*r%Intellectual==1)
{
a=Physical*Emotional*r;
break;
}
for(r=0;;r++)
if(Physical*Intellectual*r%Emotional==1)
{
b=Physical*Intellectual*r;
break;
}
for(r=0;;r++)
if(Emotional*Intellectual*r%Physical==1)
{
c=Emotional*Intellectual*r;
break;
}
//		System.out.println(a+" "+b+" "+c);

Scanner input=new Scanner(System.in);
int p,e,i,d, n,m=0;
while(input.hasNext())
{
p=input.nextInt();
e=input.nextInt();
i=input.nextInt();
d=input.nextInt();
if(p==-1&&e==-1&&i==-1&&d==-1) break;

Poj1006 Moth=new  Poj1006();
//			System.out.println(Moth.Lcm3(Physical,Emotional,Intellectual));
n=((a*i+b*e+c*p-d)%(Moth.Lcm3(Physical,Emotional,Intellectual)/*三个除数的最小公倍数*/));
if(n>0)
System.out.printf("Case %d: the next triple peak occurs in %d days.\n",++m,n);
else
System.out.printf("Case %d: the next triple peak occurs in %d days.\n",++m,21252-d);
}
input.close();
}
}

简化一点,能事先算出来的就事先算出来:

import java.util.Scanner;
public class Poj1006_简化代码 {
public static void main(String[] agrs)
{
Scanner input=new Scanner(System.in);
int p,e,i,d, n,m=0;
while(input.hasNext())
{
p=input.nextInt();
e=input.nextInt();
i=input.nextInt();
d=input.nextInt();
if(p==-1&&e==-1&&i==-1&&d==-1) break;

n=(5544*p+14421*e+1288*i-d)%21252/*三个除数的最小公倍数*/;
if(n>0)
System.out.printf("Case %d: the next triple peak occurs in %d days.\n",++m,n);
else
System.out.printf("Case %d: the next triple peak occurs in %d days.\n",++m,21252-d);
}
input.close();
}
}



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