打卡第三十天

POJ1006 UVA756 UVALive5421 Biorhythms【中国剩余定理】

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

问题分析:

本题可以直接用中国剩余定理来解,同余方程如下:

X≡p(mod 23)

X≡e(mod 28)

X≡i(mod 33)

其中,23、28和33是两两互素的,满足中国剩余定理的前提条件。

程序说明:

这里给出两个版本的C语言程序,一个是使用中国剩余定理来解,另外一个使用试探法来解(时间上可行,代码比较简洁)。


AC的C语言程序(程序中有C++的注释,需要C++的编译):
 

/* POJ1006 UVA756 UVALive5421 Biorhythms */
 
#include <stdio.h>
 
// 递推法实现扩展欧几里德算法
long exgcd(long a, long b, long  *x, long *y)
{
    long x0=1, y0=0, x1=0, y1=1;
    long r, q;
    *x=0;
    *y=1;
 
    r = a % b;
    q = (a - r) / b;
    while(r)
    {
        *x = x0 - q * x1;
        *y = y0 - q * y1;
        x0 = x1;
        y0 = y1;
        x1 = *x;
        y1 = *y;
 
        a = b;
        b = r;
        r = a % b;
        q = (a - r) / b;
    }
    return b;
}
 
// 扩展欧几里德算法求逆元
long minv(long a, long p)
{
    long x, y;
 
    exgcd(a, p, &x, &y);
 
    return x<0 ? x+p : x;
}
 
// 中国剩余定理(Chinese remainder theorem, CRT)
long crt(long a[], long m[], int n)
{
    long bm=1, mi, x=0;
    int i;
 
    for(i=0; i<n; i++)
        bm *= m[i];
    for(i=0; i<n; i++) {
        mi = bm / m[i];
        x += a[i] * mi * minv(mi, m[i]);
        x %= bm;
    }
 
    return x;
}
 
int main(void)
{
    long p, e, i, d;
    long a[3], m[3];
    long x, bm;
    int ncase = 1;
    for(;;) {
        scanf("%ld%ld%ld%ld", &p, &e, &i, &d);
        if(p==-1 && e==-1 && i==-1 && d==-1)
            break;
        a[0] = p;
        a[1] = e;
        a[2] = i;
        m[0] = 23;
        m[1] = 28;
        m[2] = 33;
 
        bm = 23 * 28 * 33;
        x = crt(a, m, 3);
        while(x<=d)
            x += bm;
 
        printf("Case %d: the next triple peak occurs in %ld days.\n", ncase++, x-d);
    }
 
    return 0;
}

AC的C语言程序:

/* POJ1006 UVA756 UVALive5421 Biorhythms */
 
#include <stdio.h>
 
int main(void)
{
    int p, e, i, d;
    int date, caseno=1;
    while(scanf("%d%d%d%d", &p, &e, &i, &d)) {
        if(p == -1)
            break;
        date = d;
        d++;
        while((d - p) % 23 != 0)
            d++;
        while((d - e) % 28 != 0 || (d - i) % 33 != 0)
            d += 23;
        printf("Case %d: the next triple peak occurs in %d days.\n", caseno++, d - date);
    }
 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值