USTCOJ1373 母牛出生问题

题目:一头母牛从出生后,每两年可以生下一头母牛,即在第二年和第四年分别可产下一头母牛,出生后第五年将会死去。假设现在有一头牛,N年后总共有多少头牛?

链接:http://acm.ustc.edu.cn/ustcoj/problem.php?id=1373

本题有两种解法。

解法一分析如下(原文在此):

用一个大小为5的整形数组x[5]来保存牛的个数,x[i]表示当前有x[i]头年龄为i的牛。牛出生的时候为0岁,在二岁和四岁的时候生一个小牛,在五岁的时候死去。

初始只有1头0岁的牛,x[0]=1,x[1~4]=0,随后每一年,所有牛都长一岁,且2岁和4岁的牛会生一个小牛。
第一年:x[1]=1,x[2~4]=0,x[0]=0没有小牛出生。
第二年:x[1]=0,x[2]=1,x[3]=0,x[4]=0,x[0]=1,出生了1头小牛,为0岁
第三年:x[1]=1,x[2]=0,x[3]=1,x[4]=0,x[0]=0,没有小牛出生
第四年:x[1]=0,x[2]=1,x[3]=0,x[4]=1,x[0]=2,有2头小牛出生,为0岁
第五年:x[1]=2,x[2]=0,x[3]=1,x[4]=0,x[0]=0,没有小牛出生
也就是说对于每一年,今年i(i>0)岁牛的头数等于去年i-1岁牛的头数,0岁小牛的头数等于今年年2岁和4岁牛的头数之和,也就是:
x[4]=x[3];
x[3]=x[2];
x[2]=x[1];
x[1]=x[0];
x[0]=x[2]+x[4];
最终x[0~4]之和就是所有牛的头数。
代码如下:

#include <stdio.h>
int main()
{
    int N;
    scanf("%d",&N);
    int x[5]={1,0,0,0,0};
    for (int i=1;i<N+1;i++)
    {
        x[4]=x[3];
        x[3]=x[2];
        x[2]=x[1];
        x[1]=x[0];
        x[0]=x[2]+x[4];
    }
    printf("%d",x[0]+x[1]+x[2]+x[3]+x[4]);
    return 0;
}

分析可知,每过一年,所有牛都增长一岁。也都由新的牛出生。在上述代码中,通过数组的赋值来模拟这一过程。但事实上,赋值操作并不是必须的。此外,上述代码并不能通过OJ,因为它只处理了一组数据。我们当然可以在外侧添加一层循环来处理多组数据。但这样效率太低,我们完全可以预先将前50年的牛总数情况计算并存储在数组中,于是计算n年后的牛的总数就变成了一个查询操作。代码如下:

/**********
*RunId: 78578
*Author: fortest
***********/
#include <cstdio>
#include <cstring>

class Cattles
{
	int x[5];
	int cur;
public:
	Cattles()
    {
        memset(x, 0, sizeof(x));
        x[0] = 1;
        cur = 4;
    }
    void increase()
    {
        x[cur] = x[(cur+4)%5] + x[(cur+2)%5];
        cur += 4;
        cur %= 5;
    }
    int getSum()
    {
        int sum = 0, i = 5;
        while (i--)
            sum += x[i];
        return sum;
    }
};

int main()
{
    Cattles cattle;
    int ans[55] = {1};
    for (int i = 1; i < 55; i++)
    {
        cattle.increase();
        ans[i] = cattle.getSum();
    }
    int n;
    while (scanf("%d", &n) != EOF)
        printf("%d\n", ans[n]);
    return 0;
}


解法二:

在稿纸上写出前14年牛的总数情况,如下:

年份    0     1     2     3     4     5     6     7     8    9    10     11     12   13     14
总数    1     1     2     2     4     3     6     5     10   8    16     13     26   21     42
观察上述数据,我们会发现,对于奇数年份,总数分别是:1、 2、 3、 5、 8、13 ....而这,恰恰就是一个Fibonacci数列。而偶数年的牛的总数,总是前一年的两倍。

了解了这一规律,那么编码就不是问题了。可参考如下代码实现:

/**********
*RunId: 74280
*Author: bairui
***********/
#include <iostream>
using namespace std;
#define MXN 50

int main()
{
    int a[MXN / 2 + 1] = {1, 2}, n;
    for (int i = 2; i <= MXN / 2; i++)
        a[i] = a[i - 1] + a[i - 2];
    while (cin >> n)
        cout << (n % 2 ? a[n >> 1] : a[(n >> 1) - 1] << 1) << endl;
    return 0;
}

你可能感兴趣的:(奶牛,USTCOJ1373)