【算法】兔子繁殖之斐波那契數(shù)列


整理一下經(jīng)典算法用C/C++實現(xiàn),并思考總結(jié)

開拓大腦的算法

題目:有一對兔子,從出生后第3個月起每個月都生一對兔子,小兔子長到第三個月后每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數(shù)為多少?

常規(guī)解法

讀題之后,我直接著手進(jìn)行解題:

思路:設(shè)置2個變量分別保存成年兔子數(shù),幼年兔子數(shù)量,設(shè)置一個計數(shù)器分組分別計算每對小兔子還有幾個月成年,成年后加入成年兔子。成年兔子每月產(chǎn)下幼年兔子加入幼年兔子。

void rabitNormal(int month){
    const int MAX_SHALL_RABIT = 1000;//最大小兔子數(shù)量(這個算法用數(shù)組做有局限性,最大只能MAX_SMALL_RABIT個兔子)
    int big_rabits = 0;//大兔子數(shù)量(初始都是小兔子)
    int small_r = 1;//小兔子數(shù)量
    short small_rabits[MAX_SHALL_RABIT];
    small_rabits[0]=2;//初始化第一對小兔子計數(shù)器
    int idx = 1;
    for (int i=0; i<month; i++) {//每個月更新
        for (int j=0; j<idx; j++) {
            if(small_rabits[j]>0){
                small_rabits[j]--;
                if(small_rabits[j]==0){//第三個月
                    big_rabits ++;//大兔子增加
                    small_r--;//小兔子減少
                }
            }
        }
        for(int j=0;j<big_rabits;j++){
            small_rabits[idx++] = 2;//每對大兔子生一對小兔子
            small_r++;//小兔子數(shù)量增加
        }
    }
    cout<<big_rabits+small_r<<endl;//打印大兔子小兔子總和
}

這個方法直接從實現(xiàn)角度來解決這個問題,就事論事,不太優(yōu)雅。

遞歸算法

因為每對兔子從出生到生產(chǎn)的過程是一致的,所以我考慮是不是封裝一個方法來表示兔子的這一過程,然后用遞歸實現(xiàn)

//遞歸實現(xiàn) 返回第一對兔子和之后所有小兔子生下的總兔子對數(shù)
int rabits(int month){
    int r = 0;
    for(int i=2;i<=month;i++){
        r+=rabits(month-i);//從第3個月起每個月生一堆兔子
    }
    return 1 + r;//這只兔子升的小兔子的總對數(shù)
}

這個方法我認(rèn)為從解決問題的角度不失為一個好方法。但對規(guī)律問題考慮不深入,也屬于就事論事。

斐波那契數(shù)列

網(wǎng)上看了正規(guī)解法后發(fā)現(xiàn),這道題表現(xiàn)的本質(zhì)就是斐波那契數(shù)列 f(0)=0,f(1)=1...f(n)=f(n-1)+f(n-2) (當(dāng)前項等于前兩項之和)。這一數(shù)列強(qiáng)大之處我還無法深入體會,我就整理下如何讓兔子生產(chǎn)和斐波那契數(shù)列聯(lián)系起來:

思考過程
1.第一個月1對幼年兔子,0對成年兔子
2.第二個月把幼年兔子加入成年兔子(因為第3個月生產(chǎn)出的幼年兔子等于當(dāng)月的成年兔子),0對幼年,1對成年
3.第三個月幼年兔子對數(shù) = 前月成年兔子對數(shù)1,成年兔對數(shù) = 前月幼兔對數(shù)+前月成年對數(shù)=0+1=1
總結(jié)公式:
兔子總對數(shù) = 成年兔子對數(shù)+幼年兔子對數(shù)
成年兔子對數(shù) = 前月成年兔子對數(shù)+前月幼年兔子對數(shù) = 前月總對數(shù)
幼年兔子對數(shù) = 前月成年兔子對數(shù) = 大前月兔子總對數(shù)(由上條公式得到)
最終推導(dǎo)公式:兔子總對數(shù) = 前月兔子總對數(shù)+大前月兔子總對數(shù)! 這個公式正好符合Fibonacci數(shù)列

void rabitFibonacci(){
    long f1,f2;
    int i;
    f1=f2=1;
    for(i=1;i<=20;i++)
    {
        printf("%12ld %12ld",f1,f2);
            if(i%2==0) printf("\n");/*控制輸出,每行四個*/
            f1=f1+f2;/*前兩個月加起來賦值給第三個月*/
            f2=f1+f2;/*前兩個月加起來賦值給第三個月*/
    }
}

整個推導(dǎo)過程為了讓幼年兔子對數(shù)更純凈(保證都是上月生產(chǎn)的兔子),次月我們就把前一個月的幼年兔子并入成年了,這是由于從客觀上來說

  1. 當(dāng)月成年對數(shù)決定次月幼年對數(shù)同時和當(dāng)月幼年對數(shù)一起決定當(dāng)月總對數(shù)
  2. 當(dāng)月幼年對數(shù)和當(dāng)月成年對數(shù)決定次月成年對數(shù)

所以以上對幼年對數(shù)當(dāng)月的“純凈”處理有利于對幼年對數(shù)的直接使用(試想一下如果幼年對數(shù)中混有新生的和上個月生的,你該如何處理它)。
從這推導(dǎo)過程的構(gòu)架和實際推導(dǎo)過程中,我認(rèn)為變量定義功能的明確性和純凈性非常重要。我要的不是這個數(shù)列和公式的直接應(yīng)用,而是這個推導(dǎo)過程。想想當(dāng)三個月變成四個月,變成五個月該怎么來推導(dǎo)?

小結(jié):3個算法前2個算法是我自己寫,第3個方法是參考網(wǎng)上的,推導(dǎo)過程是自己模擬的,雖然花了不少時間做推導(dǎo),但我覺得還是值得的,因為我現(xiàn)在最缺的就是一顆萬事靜心思考本質(zhì)的心,推導(dǎo)的方式固然重要,但這顆探究本質(zhì)的心更重要

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 斐波那契數(shù)列之兔子繁殖問題 據(jù)說很多枯燥的算法問題都是和生活密切相關(guān)的,畢竟很多算法都是人們有實際的需求才慢慢進(jìn)入...
    再見遠(yuǎn)洋閱讀 1,706評論 0 4
  • 斐波那契是意大利的數(shù)學(xué)家.他是一個商人的兒子.兒童時代跟隨父親到了阿爾及利亞,在那里學(xué)到了許多阿拉伯的算術(shù)...
    米塔塔閱讀 5,654評論 5 11
  • 假設(shè)第1個月有1對剛誕生的兔子,第2個月進(jìn)入成熟期,第3個月開始生育兔子,而1對成熟的兔子每月會生1對兔子,兔子永...
    rainchxy閱讀 8,332評論 0 1
  • 今晚和甜甜寫了幾個字,又發(fā)生了寫3的情景。發(fā)火不解。自己寫出秦來也很驚喜的說。我也會寫字啦! 事后想想是自己有點(diǎn)著...
    甜甜媽正面管教之路閱讀 262評論 0 0
  • 作為咨詢界的黃埔軍校,麥肯錫公司是優(yōu)秀職場人的輸出源。上周讀到一本不錯的書《麥肯錫精英的談判策略:商務(wù)人不可不知的...
    海咸河淡閱讀 589評論 3 5

友情鏈接更多精彩內(nèi)容