POJ1006 Biorhythms 题解

该篇文章介绍了如何使用孙子定理解决实际问题,涉及到了数论、算法和时间序列分析,旨在计算个人生理、心理和智力周期峰值再次重合的具体日期。
摘要由CSDN通过智能技术生成
题目内容大意

题目大意:人有生理,心理以及智力的一个循环,分别经过23,28,33天一个循环到达顶峰。

输入:给你4个数,在年初的时候距离上一次的生理,心理,智力的顶峰的时间p,e,i。 以及这个年已经过了几天了d。

输出:计算下一次三项同时达到顶峰的时间。

个人想法:

这个问题一开始想通过算法解决,发现有点困难。去网上找了题解。说的是孙子定理或者是中国剩余定理,或者是中国余数定理。如果想看视频了解孙子定理,可以去西瓜视频上找李永乐老师讲《韩信点兵》的视频,李永乐老师讲孙子定理​​​​​


PART1 孙子定理 如果孙子定理视频看明白了可以直接到PART2 到题目里的应用

《孙子定理解析》如果有不对的地方请指正

引入韩信点兵

韩信点兵的时候:

3人一排 余2人,5人一排 余3人 7人一排 余2人

问有多少兵。

一、列举法

(1)

除以3余2的数有:2,5,8,11,14,17,23,26,29...

除以5余3的数有:3,8,13,18,23,28...

除以7余2的数有:2,9,16,23,30...

可以找到他们三者共同的数为23,后面可能也有

(2)由于3,5,7三个数互质,所以他们的最小公倍数为 3*5*7 = 105

所以韩信的兵可能有 23 + 105 * n  其中n为自然数

二、孙子算经的方法

明代数学家的口诀:

三人同行七十稀,

五树梅花廿一枝,

七子团圆月正半,

除百零五便得知。

解释:

除以3的余数 * 70 + 除以5的余数 * 21 + 除以7的余数 * 15得到的和最后对105取余数就可以得到最小的人数。比如韩信点兵的人数 2 * 70 + 3 * 21 + 2 * 15 = 233 。233 对 105 取余数 得到 23 和列举法的答案一致

问题的关键就在于70,21,15这三个数是怎么得来的:

三个数3,5,7

分析:

70是5和7的倍数,但是70 mod 3 = 1

21是3和7的倍数,但是21 mod 5 = 1

15是3和5的倍数,但是15 mod 7 = 1

所以我们只要找到其中两个数的倍数但是对另外一个数取余得到1就可以了。这也可以解释为什么要这些数乘以余数,因为原来余数是1,如果要得到余数是3,那么这个数直接乘3就可以了,因为这个数是另外两个数的倍数不管乘以多少,对另外的两个数而言都是可以整除的。


PART2 题目解析

按照孙子定理23,28,33

23和28的最小公倍数是644,644 mod 33 = 17 因为17*2刚好等于34

644 * 2 = 1288 mod 33 = 1 所以33的余数 要乘1288

23和33的最小公倍数是759,759 mod 28 = 3,这个数要凑的比较多,3*19 mod 28 = 1

759*19 = 14421 所以28的余数 要乘14421

28和33的最小公倍数是924,924 mod 23 = 4  4*6 = 24 刚好比23多1

924 * 6 = 5544  所以23的余数 要乘以5544。

最后把结果套进题目。因为题目是当天不算的,所以最后如果得到的数是0或者是负数,还要加上他们3个数的最小公倍数,也就是三项同时到达顶峰的循环时间。题目已经告诉我们他们三者的最小公倍数是21252

最后的公式应该就是 (p * 5544 + e * 14421 + i * 1288 + 21252 - d) mod 21252

如果结果等于0的话,就再加一个21252。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

int main()
{
    int p, e, i, d;
    int nums = 0;
    while(cin>>p>>e>>i>>d){
        if (p == -1 && e == -1 && i == -1 && d == -1) break;
        nums += 1;
        int temp = (p * 5544 + e * 14421 + i * 1288 + 21252 - d) % 21252;
        if (temp == 0) temp += 21252;
        printf("Case %d: the next triple peak occurs in %d days.\n", nums, temp);
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值