[算法設計與分析]4.1.1遞推法(兔子繁殖+最大公約數3種方法)

#include<stdio.h>
#include<iostream>

using namespace std;
const int N = 12;//定義所求月份
/*著名意大利數學家Fibonacci曾提出一個問題:有一對小兔子,從出生後第3個月起每個月都生一對兔子。
小兔子長到第3個月後每個月又生一對兔子。按此規律,假設沒有兔子死亡,第一個月有一對剛出生的小兔子,
問第n個月有多少對兔子?*/
//總體思路是f(n)=f(n-2)+f(n-1) 即本月的兔子=本月新出生兔子+以前留下的老兔子
//因爲2個月之前的兔子此時全部具有繁殖能力 因此新兔子的數量=f(n-2)
//又因爲前一個月的兔子全部活下來了 因此本月的老兔子數量=f(n-1)
void RabbitBreeding1(int n);
void RabbitBreeding2(int n);
void RabbitBreeding3(int n);

//求最大公約數
//1.輾轉相除法:取兩個數中最大的數做除數,較小的數做被除數,用最大的數除較小數,
//如果餘數爲0,則較小數爲這兩個數的最大公約數,
//如果餘數不爲0,用較小數除上一步計算出的餘數,直到餘數爲0,則這兩個數的最大公約數爲上一步的餘數。
void GreatestCommonDivisor1();
//2.相減法:取兩個數中的最大的數做減數,較小的數做被減數,用最大的數減去小數,
//如果結果爲0,則被減數就是這兩個數的最大公約數,
//如果結果不爲0,則繼續用這兩個數中最大的數減較小的數,直到結果爲0,則最大公約數爲被減數。
void GreatestCommonDivisor2();
//3.窮舉法:將兩個數作比較,取較小的數,以這個數爲被除數分別和輸入的兩個數做除法運算,
//被除數每做一次除法運算,值減少1,直到兩個運算的餘數都爲0,則該被除數爲這兩個數的最大公約數。
void GreatestCommonDivisor3();

int main ()
{
    RabbitBreeding1(N);
    RabbitBreeding2(N);
    RabbitBreeding3(N);

   GreatestCommonDivisor1();
   GreatestCommonDivisor2();
   GreatestCommonDivisor3();
}


//c = a + b; a = b; b = c;做數據的遷移 每次循環只進行了一個月的遞推 因此總共需要進行n次 ab代表1月和2月 因此循環部分爲3->n
void RabbitBreeding1(int n)
{
    int i, a = 1, b = 1, c = 0;
    cout << "1月:" << a << endl << "2月:" << b << endl;

    for(i = 3; i <= n; i++)
    {
        c = a + b;
        a = b;
        b = c;
        cout << i << "月:" << c << endl;
    }
    cout << "\n第" << n << "月共有兔子:" << c << endl;
}

//c=a+b; a=b+c; b=c+a; 構造循環不變式 這樣循環一次遞推3步 循環次數減少 爲n/3次
void RabbitBreeding2(int n)
{
    int i, a = 1, b = 1, c = 0;

    for(i = 1; i <= n / 3; i++)
    {
        c = a + b;
        a = b + c;
        b = c + a;
    }
    cout << "\n\n第" << n << "月共有兔子:" << c << endl;
}

//可以無需引入第三個變量 a=a+b;b=a+b; 此時循環一次遞推2步
void RabbitBreeding3(int n)
{
    int i, a = 1, b = 1;

    for(i = 1; i <= (n - 2) / 2 ; i++)//因爲ab有初始值 已經代表了2個月 因此所求月份是n-2 同時因爲每次遞推2步 因此/2
    {
        a = a + b;
        b = b + a;
    }
    cout << "\n\n第" << n << "月共有兔子:" << b << endl;
}

//輾轉相除法
void GreatestCommonDivisor1()
{
    int a = 36, b = 5;//求a,b的最大公約數
    int prea = a, preb = b;

    int c = a % b;
    while(c)
    {
        a = b;
        b = c;
        c = a % b;
    }
    cout << endl << prea << "和" << preb << "最大公約數是:" << b <<endl;
}
//相減法
void GreatestCommonDivisor2()
{
    int a = 36, b = 5;//保證a>b;
    int prea = a, preb = b;
    int c = a - b;
    while(c)
    {
        a = b > c ? b : c;//保證a>b;
        if(a == b)//被減數>減數>差 此時a,b的值依次後延 即a=b, b=c;
            b = c;
        //不滿足if條件說明b<c此時只需要a=c即可滿足被減數>減數
        c = a - b;
    }
    cout << endl << prea << "和" << preb << "最大公約數是:" << b <<endl;
}
//窮舉法
void GreatestCommonDivisor3()
{
    int a = 36, b = 5;
    int mins = a > b ? b : a;//求出兩數中較小的那個

    while(a % mins || b % mins)//兩個運算的餘數都不爲0 (德摩根)
    {
        mins--;
    }
    cout << endl << a << "和" << b << "最大公約數是:" << mins <<endl;
}


發佈了55 篇原創文章 · 獲贊 17 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章