题目:一头母牛从出生后,每两年可以生下一头母牛,即在第二年和第四年分别可产下一头母牛,出生后第五年将会死去。假设现在有一头牛,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;
}