母牛养殖日记 - 类斐波那契数列通用递推公式的推导
1.引例:母牛的故事
在养殖类的斐波那契类型问题中,经常出现生长的月数改变的情况。比如这道题:
ACM2018
Problem Description
有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
Input
输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0 < n < 55),n的含义如题目中描述。
n = 0表示输入数据的结束,不做处理。
Output
对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。
这道题的解析:
这里我们先不把母牛换成蛤蟆,看能否解决这个问题。
母牛出生的年份算作这头母牛的第1年而不是第0年;
总时间的进程始于第1年而不是第0年。
容易找到递推公式:
f(n)=⎩⎨⎧1,2,3,f(n−1)+f(n−3),n=1n=2n=3n≥4
下面给出证明。
用 d 表示成年母牛,用yi(i=1,2,3)表示 i 岁的小牛,则 f(n)=df(n)+y3f(n)+y2f(n)+y1f(n)。
又有 f(n)=f(n−1)+df(n) ,因为y3的小牛在变成母牛时会立即生牛。
又有 df(n)=df(n−1)+y3f(n−1)
又有 yif(n)=yi−1f(n−1)
将 n 替换为 n−i(i=1,2),得:
f(n)=f(n−1)+df(n)=f(n−1)+df(n−1)+y3f(n−1)=f(n−1)+df(n−2)+y3f(n−2)+y2f(n−2)=f(n−1)+(df(n−3)+y3f(n−3)+y2f(n−3)+y1f(n−3) )=f(n−1)+f(n−3)
证明完毕。
由此可见,养殖母牛的问题与养殖兔子和蛤蟆一样,都是可以通过递推解决的。
在这个问题中,由于既要调用f(n−1)又要调用f(n−3),所以递归很慢,时间复杂度高达 O(2n) ,故应采用递推的方式进行计算。
下面给出代码(C语言):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <stdio.h>
int bear(int); int main(void) { int n=1; do { scanf("%d",&n); if(n) { printf("%d\n",bear(n)); } }while(n); return 0; }
int bear(int n) { int i; int cows[55]={0,1,2,3}; if(n<4) { return cows[n]; } for(i=4;i<=n;i++) { cows[i]=cows[i-1]+cows[i-3]; } return cows[n];
}
|
2.一般性结论
由上式可以看出,式子把 df(i) 一直展开到含y1f(j)的项为止,一共进行了m 步,其中m是未成年小牛的年龄种类数。本例中有3个年龄段的未成年小牛,所以m=3。而每展开一步,df(n)的展开式的下标都减1,所以,最终由df(i)展开的式子,就是f(n−m)。
因此,对于类斐波那契数列问题,其递推公式为:f(n)=f(n−1)+f(n−m) ,其中m为未成年动物的年龄种类数。