递归算法 基础总结(斐波那契)(进制转换)(辗转相除法)(汉诺塔总结)(hdu2032杨辉三角)

递归的概念:

递归就是某个函数直接或间接调用自身的问题求解过程。
通过将自身问题划分成相同性质的子问题的求解过程,这些小问题的求解过程较容易,小问题的解就构成了原问题的解。

递归的设计思路:

要解决一个规模为n的问题,先看规模为n-1(或者n-k或者n/2,总之是比原问题规模小)的问题是否和原问题有同样的性质,如果性质相同,那这个问题应该可以用递归算法解决

特点:

1,递归就是在函数里或过程中调用自身。
2,在递归过程中必须有一个明确的结束条件,即递归出口。
3,递归解题简介,递归效率不高,但是代码不多。一般不提倡用递归。
4,递归时系统为每一层的返回点,局部变量,提供栈来存储。递归次数多了,容易发生栈溢出。

关键

1.找出递推关系式
2.找到递归终止条件
注:深层次的递归可能导致栈溢出,可以考虑使用全局数组或动态分配数组

在这里插入图片描述

举例:

1:求n的阶乘

递推关系式 f(x)=x*f(x-1)
终止条件 乘到1后,x-1=0,结束递归返回1

#include<stdio.h>
long long int f(int x)
{
    if(x==0)
        return 1;
    else
        return x*f(x-1);
}
int main()
{
    int n;
    scanf("%d",&n);
    long long int ans=f(n);
    printf("%lld",ans);
    return 0;
}
2:斐波那契递归

基本定义
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368…

斐波那契数列
特别指出:第0项是0,第1项是第一个1。
这个数列从第3项开始,每一项都等于前两项之和。

一般思路:f(n)=f(n-1)+f(n-2)
int fabonacci(int n)
{
    if(n <0)
    	return -1;
    else if(n==0)
    	return 0;
    else if(n==1)
    	return 1;
    else
    	return fabonacci(n)+fabonacci(n-1);
 }
与改进后思路的对比:
#include<stdio.h>

int n1 = 0;//记录普通的递归次数
int n2 = 0;//优化的递归次数

//普通递归函数
int fibon(int n)
{
	n1 ++;
	if(n <= 2)//递归出口
	{
		return 1;
	}
	return fibon(n-1) + fibon(n-2);
}

//优化后的递归函数
int fibonac(int a,int b,int n)
{
	n2 ++;
	if(n > 2)
	{
		return fibonac(a+b,a,n-1);
	}
	return a;
}
int main()
{
	int n = 10;//第几个斐波那契数列

	int a = 1; //斐波那契数列的第一项
	int b = 1;//第二项

	int i = fibon(n);//普通的递归
	int j = fibonac(a,b,n);//优化后的递归

	printf("第n个fibon数是--%d\n",i);
	printf("次数--%d\n",n1);

	printf("第n个fibon数是--%d\n",j);
	printf("次数--%d\n",n2);

	return 0;
}

对比一下:
在这里插入图片描述

3:将任意十进制转换为K(1<k<10)进制

Input
第一行输入一个数n,表示n(0<n<=100)组测试数据
接下来的n行每一行输入一个数 m和k表示将m转化为相应的进制表示
(0<m<100000000)

Output
输出转化完成后的数

Sample Input
2
9 7
13 3
Sample Output
12
111

AC代码:

#include <bits/stdc++.h>
using namespace std;
void han(int m,int k)
{
    if(m/k!=0)
    {
        han(m/k,k);                
        printf("%d",m%k);
    }
    else
        printf("%d",m);
}
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int m,k;
        cin>>m>>k;
        han(m,k);
        printf("\n");
    }
    return 0;
}
顺便总结一下模板:一个十进制数m转化成k(k<10)进制
void han(int m,int k)
{
    if(m/k!=0)
    {
        han(m/k,k);               
        printf("%d",m%k);
    }
    else
        printf("%d",m);
}
4:递归法的应用:辗转相除法求最大公约数:
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
    if(a%b==0)
        return b;
    else
        return gcd(b,a%b);
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d",gcd(a,b));
    return 0;
}

在这里插入图片描述

5: 汉诺塔问题总结:

汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

首先,递归的组成有两部分,一个是递归体,一个是递归结束条件。 其本质在于重复 ,因此找到了重复的内容就能推导出递归体。

对此汉诺塔题目来说,将三个柱子(初始柱,过渡柱,目标柱)分别标记为x,y,z(注:这里的柱子相当于实参,字母相当于形参)

这个搬圆盘活动抽象后可分成三步:

  1. 将初始柱上除最下面的圆盘以外的圆盘全部搬到过渡柱上;就是把n-1个圆盘从x柱子移到y柱子上去。就是han(n-1,x,z,y);
  2. .将初始柱上最下面的圆盘搬到目标柱上; 就是printf("%c–>%c\n",x,z);
  3. 将过渡柱上的圆盘全部搬到目标柱上。 这一步也可以看做是第一步的逆向操作。就是han(n-1,y,x,z);

一切搬圆盘都是在重复上面三个步骤,因此,这三步便是一个递归体。

汉诺塔问题源于印度神话
那么好多人会问64个圆盘移动到底会花多少时间?那么古代印度距离现在已经很远,这64个圆盘还没移动完么?我们来通过计算来看看要完成这个任务到底要多少时间?
我们首先利用数学上的数列知识来看看
F(n=1)=1,F(n=2)=3,F(n=3)=7,F(n=4)=15……F(n)=2F(n-1)+1;
我们使用数学归纳法可以得出
计算时间的通项式:F(n)等于2n-1。
当n为64时F(n=64)=18446744073709551615。
我们假设移动一次圆盘为一秒,那么一年为31536000秒。那么18446744073709551615/31536000约等于584942417355天,换算成年为5845.54亿年。
目前太阳寿命约为50亿年,太阳的完整寿命大约100亿年。所以我们整个人类文明都等不到移动完整圆盘的那一天。。。

写一下移动过程:

其中han(3,‘a’,‘b’,‘c’);表示一共3个盘子,初始时全在a柱上,要经过b这个过度柱子,全把盘子移动到c柱子上去。

#include <bits/stdc++.h>
using namespace std;
int han(int n,char x,char y,char z)
{
    if(n==1)
        printf("%c-->%c\n",x,z);
    else
    {
        han(n-1,x,z,y);
        printf("%c-->%c\n",x,z);
        han(n-1,y,x,z);
    }
}
int main()
{
    han(3,'a','b','c');//3个盘子的话
    return 0;
}

在这里插入图片描述

hdu2032杨辉三角

Problem Description
还记得中学时候学过的杨辉三角吗?具体的定义这里不再描述,你可以参考以下的图形:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
Input
输入数据包含多个测试实例,每个测试实例的输入只包含一个正整数n(1<=n<=30),表示将要输出的杨辉三角的层数。
Output
对应于每一个输入,请输出相应层数的杨辉三角,每一层的整数之间用一个空格隔开,每一个杨辉三角后面加一个空行。
Sample Input
2 3
Sample Output
1
1 1

1
1 1
1 2 1

#include<stdio.h>
int main()
{
    int I[32][32]={0};
    for(int i=0;i<31;i++)
        I[i][0]=1;
    for(int i=1;i<31;i++)
    {
        for(int j=1;j<=i;j++)
            I[i][j]=I[i-1][j-1]+I[i-1][j];
    }
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=i;j++)
            {
                printf("%d",I[i][j]);
                if(j!=i)printf(" ");
                if(j==i)printf("\n");
            }
        }
        printf("\n");
    }
    return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我理解了你的问题。下面是针对递归算法解决汉诺塔问题的实验报告,包括测试分析与总结。 ## 一、实验目的 本次实验旨在通过编写递归算法解决汉诺塔问题,掌握递归的思想与算法,并对递归算法进行测试分析,总结递归算法的优缺点。 ## 二、实验内容 ### 1. 算法思想 汉诺塔问题是一个经典的递归问题,它描述了如何将 $n$ 个盘子从一根柱子移动到另一根柱子,其中有一个中转柱子。要求每次只能移动一个盘子,并且大盘子不能放在小盘子上面。 递归解法如下: - 将 $n-1$ 个盘子从起始柱子移动到中转柱子; - 将第 $n$ 个盘子从起始柱子移动到目标柱子; - 将 $n-1$ 个盘子从中转柱子移动到目标柱子。 这样,问题就被拆分为了三个子问题,每个子问题都可以看作是一个更小的汉诺塔问题。因此,可以通过递归调用自身来解决整个问题。 ### 2. 算法实现 基于上述算法思想,我们可以编写如下的递归函数: ```python def hanoi(n, start, target, auxiliary): if n == 1: print(f"Move disk from {start} to {target}") else: hanoi(n-1, start, auxiliary, target) print(f"Move disk from {start} to {target}") hanoi(n-1, auxiliary, target, start) ``` 其中,`n` 表示盘子的数量,`start` 表示起始柱子,`target` 表示目标柱子,`auxiliary` 表示中转柱子。 ### 3. 算法测试 为了测试上述算法的正确性,我们可以分别测试不同数量的盘子时,算法的输出是否符合预期。 例如,当盘子数量为 3 时,算法的输出应该为: ``` Move disk from A to C Move disk from A to B Move disk from C to B Move disk from A to C Move disk from B to A Move disk from B to C Move disk from A to C ``` 当盘子数量为 4 时,算法的输出应该为: ``` Move disk from A to B Move disk from A to C Move disk from B to C Move disk from A to B Move disk from C to A Move disk from C to B Move disk from A to B Move disk from A to C Move disk from B to C Move disk from B to A Move disk from C to A Move disk from B to C Move disk from A to B Move disk from A to C Move disk from B to C ``` 通过实际测试,我们可以发现,上述算法的输出符合预期。 ### 4. 算法分析 递归算法的时间复杂度为 $O(2^n)$,空间复杂度为 $O(n)$。由于递归算法会频繁地进行函数调用,因此在数据量较大时,递归算法的效率较低,容易出现栈溢出等问题。 ## 三、实验总结 通过本次实验,我们了解了递归算法的思想与实现,并通过针对汉诺塔问题的递归实现,加深了对递归算法的理解。同时,我们也意识到递归算法的缺点,需要在实际应用中谨慎选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值