递推与递归

一.递推

在C++中,递推算法可以通过循环或递归来实现。本文将详细介绍C++中的递推算法实现方式。

  1. 循环实现递推算法: 循环是一种常用的实现递推算法的方法。通过定义初始条件和更新规则,在每次迭代中计算出后续项的值
    #include <iostream>
    
    int main() {
        int n; // 要计算的项数
        int a = 0, b = 1; // 初始条件
        std::cout << "请输入要计算的项数:";
        std::cin >> n;
    
        std::cout << "斐波那契数列前" << n << "项为:";
        std::cout << a << " " << b << " ";
    
        for (int i = 2; i < n; i++) {
            int temp = a + b;
            std::cout << temp << " ";
            a = b;
            b = temp;
        }
    
        std::cout << std::endl;
        return 0;
    }
    

    上述代码使用循环计算斐波那契数列的前n项。通过定义初始条件a=0、b=1,然后使用for循环从第3项开始计算,每次迭代计算出当前项的值temp,并更新a和b的值。

  2. 递归实现递推算法: 递归是一种自身调用的方法。通过定义递归函数,在每次调用函数时传入不同的参数,实现对问题的分解和求解。

    上述代码使用递归函数计算斐波那契数列的前n项。递归函数fibonacci接收一个参数n,如果n为0或1,则返回相应的初始条件;否则,递归调用fibonacci函数来计算前两项的和。

  3. #include <iostream>
    
    int fibonacci(int n) {
        if (n == 0)
            return 0;
        else if (n == 1)
            return 1;
        else
            return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    int main() {
        int n; // 要计算的项数
        std::cout << "请输入要计算的项数:";
        std::cin >> n;
    
        std::cout << "斐波那契数列前" << n << "项为:";
        for (int i = 0; i < n; i++) {
            std::cout << fibonacci(i) << " ";
        }
    
        std::cout << std::endl;
        return 0;
    }
    
  4. 无论是循环还是递归实现,递推算法都可以根据给定的初始条件和更新规则,通过迭代或递归的方式计算出后续项的值。具体选择哪种实现方式取决于问题的特点和性能需求

  5. 通常情况下,用循环实现递推比用递归实现递推的时间复杂度要低一些,因为递归有时会多次重复计算相同数据,导致时间复杂度过高。所以,我们通常在递归中增加记忆化搜索,避免重复计算。

  6. #include <iostream>
    using namespace std;
    int fibo[10005]={0,1};//记忆化数组 
    int fibonacci(int n)
    {
        if(fibo[n]!=0) return fibo[n];//判断是否进行过记忆化 
        for(int i=2;i<=n;i++) fibo[i]=fibo[i-1]+fibo[i-2];//记忆化处理 
        return fibo[n];
    }
    int main()
    {
    	int t;// 要输入的次数 
        int n;// 要计算的项数
        cin>>t;
        while(t--)
        {
        	scanf("%d",&n);
    		printf("%d\n",fibonacci(n));
    	}
        return 0;
    }
    
    

    既然学会了,那就上两道题

  7. Pell数列a_1,a_2,a_3, ...的定义是这样的,a_1 = 1, a_2 = 2, ... , a_n = 2 a_{n−1} + a_{n-2}(n>2)。

    给出一个正整数k,要求Pell数列的第k项模上32767是多少。

  8. 输入:第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数k (1≤k<1000000)

  9. 输出:n行,每行输出对应一个输入。输出应是一个非负整数。

  10. 样例输入

    2
    1
    8
  11. 样例输出
    1
    408
  12. 分析:这道题其实就是一个斐波那契数列的变形,唯一需要注意的是数据范围,话不多说,直接上代码:

  13. #include<cstdio>
    const int maxN = 1000001;
    int a[maxN];
    void lcc(){
        a[1]=1;
        a[2]=2;
        for(int i=3;i<maxN;i++)
            a[i]=(2*a[i-1]+a[i-2])%32767;
    }
    int main(){
        int n;
        lcc();
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            int k;
            scanf("%d",&k);
            printf("%d\n",a[k]);
        }
        return 0;
    }
    

楼梯有n(81>n>0)阶台阶,上楼时可以一步上1阶,也可以一步上2阶,也可以一步上3阶,编程              计算共有多少种不同的走法。

输入:输入的每一行包括一组测试数据,即为台阶数n。最后一行为0,表示测试结束。

输出:每一行输出对应一行输入的结果,即为走法的数目。

样例输入:

1
2
3
4
0

样例输出:

1
2
4
7

分析:这道题看似很复杂,其实只要找对递推式,就会发现这道题很简单。从一次可以上1~3个台阶看出,f[i]=f[i-1]+f[i-2]+f[i-3]。这样一来这道题立马简单多了。话不多说,直接上代码:

#include <cstdio>
#include <cstring>
using namespace std;
int a = 1;
long long A[75];
int main(){
    A[0] = 1;
    for(int i = 1; i <= 72; i ++)
    {
        if(i - 3 >= 0)
            A[i] = A[i - 1] + A[i - 2] + A[i - 3];
        else if(i - 2 >= 0)
            A[i] = A[i - 1] + A[i - 2];
        else if(i - 1 >= 0)
            A[i] = A[i - 1];
    }
    while(a != 0)
    {
        scanf("%d", &a);
        if(a != 0)
            printf("%lld\n", A[a]);
    }
    return 0;
}

总结:递推其实并不复杂,复杂的是找对递推式,只要递推式找对,题目就迎刃而解了。

二.递归

在C++中,递归是一种常用的编程技巧,它允许函数在其自身内部调用自身。递归可以解决需要重复执行相同或类似操作的问题,通过将问题分解为更小的子问题来实现。

下面是一个使用递归算法计算阶乘的示例:

#include <iostream>
using namespace std; 
int factorial(int n) {
    if (n == 0)
        return 1;
    else
        return n * factorial(n - 1);
}

int main() {
    int num;
    cout << "请输入一个非负整数: ";
    cin >> num;

    if (num < 0) {
        cout << "输入错误,请输入非负整数!" <<endl;
        return 0;
    }

    int result = factorial(num);
    cout << num << " 的阶乘是:" << result <<endl;
    return 0;
}

在上述代码中,我们定义了一个递归函数factorial来计算给定整数n的阶乘。如果n为0,则返回1(阶乘的边界条件)。否则,递归调用factorial函数来计算n-1的阶乘,并将其与n相乘,得到n的阶乘。

需要注意的是,在使用递归时需要设置递归的终止条件,即递归函数应该能够在某个条件下终止递归。否则,递归将无限进行下去,导致堆栈溢出等问题。

递归在解决问题时具有简洁、直观的优势,但也需要注意一些潜在的问题。递归可能会占用大量的内存空间和堆栈空间,并且在某些情况下可能会导致性能问题。因此,在使用递归算法时,需要合理地选择递归的深度和递归调用的位置,以避免潜在的问题。

总结来说,递归是一种常用的编程技巧,通过函数在自身内部调用自身,可以解决需要重复执行相同或类似操作的问题。在使用递归时,需要设置递归的终止条件,并注意内存和性能方面的考虑。

众所周知,学算法,不做题是学不会的,让我们上两道题:

逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括+ - * /四个。

输入:输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出:

输出为一行,表达式的值。

可直接用printf("%f\n", v)输出表达式的值v。

样例输入:

* + 11.0 12.0 + 24.0 35.0

样例输出:

1357.000000

分析:这道题其实就是每一个运算符和两个数组成算式,这道题不仅可以使用递归,使用数据结构栈也十分简洁,但用栈解决的代码我们以后再讨论:

#include<stdio.h>  
#include<stdlib.h> 
#include<math.h>  
    
double exp()  
{  
    char a[10];  
    scanf("%s",a);
    switch(a[0])  
    {  
        case '+':return exp()+exp();
        case '-':return exp()-exp();
        case '/':return exp()/exp();
        case '*':return exp()*exp();
        default:return atof(a);  
    }
}  
int main()  
{  
    double ans;  
    ans=exp();  
    printf("%f\n",ans);  
    return 0;  
} 

总结:递归的精髓就是一句话,自己调用自己。

最后,让我们以一道递归结尾:

输入一个数,输出其素因子分解表达式。

输入:输入一个整数 n (2 <= n < 100)。

输出:输出该整数的因子分解表达式。
表达式中各个素数从小到大排列。
如果该整数可以分解出因子a的b次方,当b大于1时,写做 a^b ;当b等于1时,则直接写成a。

样例输入:

60

样例输出:

2^2*3*5

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=2;n!=1;i++)
	{
		int cnt=0;
		while(n%i==0)
		{
			n/=i;
			cnt++;
		}
		if(cnt!=0)
		{
			if(n==1)
			{
				if(cnt==1) printf("%d\n",i);
				else printf("%d^%d\n",i,cnt);
				break;
			}
			else
			{
				if(cnt==1) printf("%d*",i);
				else printf("%d^%d*",i,cnt);
			}
		}
		
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值