[算法设计与分析]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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章