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