递归就是
一个函数直接或间接地调用自身,是为直接或间接递归。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。用递归需要注意以下两点:
(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件。在递归算法中也出现了一些新的算法如return n==a?b:函数,含义为如果a为真,则表达式为值为b,否则为此前函数中算出的值。
递归函数它有一个基本部分,还有一个递归部分,即通过改变基本参数数,来逐步使n满足基本部分的条件,从而输出。在运行的过程中,它将整体分割成部分,并总是从最小的部分开始入手,当整体递归到部分时,会保留整体的信息,部分满足条件输出的结果会被回溯给整体使用,从而使得整体输出结果。每一步操作,整体都会将部分当作其中一个步骤,从而实现整体步骤的完成。代码中要有明确的在每一层传递变量和返回结果;以使递归持续下去,同时能获取下一级的结果。
例题:数字方格
如上图,有3个方格,每个方格里面都有一个整数a1,a2,a3。已知0 <= a1, a2, a3 <= n,而且a1 + a2是2的倍数,a2 + a3是3的倍数, a1 + a2 + a3是5的倍数。你的任务是找到一组a1,a2,a3,使得a1 + a2 + a3最大。
#include<bits/stdc++.h> using namespace std; int main() { int n,max=0; cin>>n; for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) { for(int k=0;k<=n;k++) { if((i+j)%2!=0)continue; if((j+k)%3!=0)continue; if((i+j+k)%5!=0)continue; if(i+j+k>max)max=i+j+k; } } } cout<<max<<endl; return 0; }
需要注意每一层的循环以及编写符合题目要求的代码。
例2:求分解因数
#include<bits/stdc++.h>using namespace std; int shu(int a,int b) { int sum=0; if(a==1) return 1; for(int i=b; i<=a; i++) if(a%i==0) { sum+=shu(a/i,i); } return sum;} int main() { int n,a; cin>>n; for(int i=0; i<n; i++) { cin>>a; cout<<shu(a,2)<<endl; } return 0;}需要注意在调用函数中每一种情况的返回值以及函数中求因数的算法,在for循环中从0开始而不是1,且因数需从2开始计算。
目前还不是很理解系统堆栈,递归边界,全局变量或局部变量在函数中的传递。
例3.放苹果
#include<bits/stdc++.h> using namespace std; int count(int m,int n) { if(n==1||m==0) return 1; if(m<n) return count(m,m); else return count(m,n-1)+count(m-n,n); } int main() { int i; cin>>i; for(;i>0;i--) { int a,b; cin>>a>>b; cout<<count(a,b)<<endl; } return 0; }
需要看成是两种情况,第一种盘子不空,即每个盘子至少放一个苹果
第二种是盘子有空的,即至少有一个盘子是空的
转换成公式的话:m个苹果,n个盘子
第一种:m-n个苹果 n个盘子
第二种:m个苹果 n-1个盘子(这里苹果还没有进行存放就先不剪掉,只是处理掉至少一个盘子不放)
心得:递归真难!且在做题时易出现错误。递归设计首先要明确递归函数的功能,设计过程中要时时记住自己递归函数
的设计目的。在解决递归问题时,急需要完全理解题意并有完整的思路,不然在编写时时常会进退两难。在用以前学的方法与
思路编写递归问题时常常会使函数运行超时,但你并不知道错在哪,这样就很难改正程序。在程序中要明确每一层的返回值
以及在何时输出函数值。