斐波那契生兔子問題(一月大兔子生a對,二月大兔子生b對,三月大兔子生c對。。。)

tothee發表於2018-05-11

        現提出一個問題:一對兔子一個月大時可生育a對兔子,兩個月大的兔子生育b對兔子,三個月大及以後的兔子生c對兔子。假設兔子不死,現有1對兔子,問N個月後有多少隻兔子。
        看起來這是一個遞推數列的問題,要注意的地方在於,第n+1個月和第n個月的關係是,f(n+1)=第n個月的一月生兔子*a+第n個月的二月生兔子*b+第n個月的三月生及以後兔子*c。試圖直接找遞推關係將是很困難的。不妨用迴圈或者遞迴用狀態轉移的思想,從第一個月順著推到n個月。
        兔子群裡隨時都是三種兔子,一月生二月生和三月生,所以我們要做的就是從頭開始,每進行一個月算出下一個月的三種兔子分別是多少,然後讓月份+1,當月份達到要求時推出即可。
        現令N=11,a=0,b=1,c=1(在這種情況下恰好構成斐波那契數列)
        遞迴版:
#include <iostream>
#include <cstdio>
using namespace std;

int total = 0,N=11;
int a=0,b=1,c=1;
void tuzi(int month,int first,int second,int third)
{
	if(month>N)
	{
		total = first + second + third;
		return ;
	}
	int f=first,s=second,t=third;
	f = first * a + second * b + third * c;
	s = first;
	t += second;
	tuzi(month+1,f,s,t);
}
int main()
{
	tuzi(1,1,0,0);
	cout<<total<<endl;
}



非遞迴版:
#include <iostream>
#include <cstdio>
using namespace std;
int a=0,b=1,c=1;
int main()
{
	int n=0;
	int f,first=1,s,second=0,t,third=0;
	while(n<11)
	{
		f=first;
		s=second;
		t=third;
		first = f*a+s*b+t*c;
		second = f;
		third += s;
		n++;
	}
	cout<<first+second+third<<endl;
}

當我們計算前11個月每月總數時,我們發現
        結果剛好是我們熟悉的斐波那契數列f(n)=f(n-1)+f(n-2)。

        剛開始看到這道程式設計題的時候我也想過會不會第n個月和前面的有某種遞推關係,但是沒多想直接用DP的思想做了,做完了再會過來看才發現剛好是斐波那契數列。現在我們來看看為什麼是這樣。
        我們用f(n),s(n),t(n),g(n)分別代表第n個月時的一月生,二月生,三月(fst是first,second,third的意思)及以後的兔子數量,和g(n)總數。
        即有g(n)=f(n)+s(n)+t(n)。
        在上圖結果中,我們隨便找三行,可以發現以下關係:
                                                    t(n)=s(n-1)+t(n-1),s(n)=f(n-1),f(n)=s(n-1)+t(n-1)。
        然後再看s(n-1)和t(n-1):    s(n-1)=f(n-2),t(n-1)=s(n-2)+t(n-2)
        帶入上面f(n)中可得            f(n)=f(n-2)+s(n-2)+t(n-2)。
        最終可得                            g(n)=s(n-1)+t(n-1)+f(n-1)+f(n-2)+s(n-2)+t(n-2),即g(n)=g(n-1)+g(n-2)

相關文章