递归调用:在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。 |
递归调用又包括直接调用和间接调用,下面举个例子(便于理解)。 |
直接调用: |
int f(int x) { int y,z; z=f(y); //在调用函数f的过程中,又要调用f函数。 return (2*z); } |
间接调用: |
int first(int x) { int b; b=second(x); return (2*b); } int second(int y) {int a; a=first (y); return 2*a); } //从这个程序可以看出这样执行会出现无终止的自身调用,所以要加入对应的判断机制,让递归在有限次数后停止。 |
下面写一个递归的简单函数(求n!) |
//编写递归函数时,必须在函数的某些地方必须使用if语句,强迫函数在执行递归函数前返回。如果不这样做函数是 永远不会返回的。 |
下面给大家整理了一些例题、 |
描述给出一个正整数a,要求分解成若干个正整数的乘积,即a = a1 * a2 * a3 * ... * an,并且1 < a1 <= a2 <= a3 <= ... <= an,问这样的分解的种数有多少。注意到a = a也是一种分解。输入第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数a (1 < a < 32768)输出n行,每行输出对应一个输入。输出应是一个正整数,指明满足要求的分解的种数样例输入2 2 20样例输出 1 4 |
#include<iostream> using namespace std; int k,n,j; void as(int p,int n) {if(p==1) {k++;return;} else { for(int i=n;i<=p;i++) {if(p%i==0) {as(p/i,i);} } }} int main() { cin>>n; for(j=1;j<=n;j++) {k=0;int t; cin>>t; as(t,2); cout<<k<<endl; } } |
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。输入第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。输出对输入的每组数据M和N,用一行输出相应的K。样例输入1 7 3样例输出 8 |
#include<iostream> #include<cstdio> using namespace std; int ss(int m,int n) { if(m==0||n==1) {return 1;} if(n>m) {return ss(m,m);} return ss(m,n-1)+ss(m-n,n); } int main() {int t,x,y; cin>>t; while(t--) {cin>>x>>y; cout<<ss(x,y)<<endl; } } |
输入输入第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 10),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。输出输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。样例输入70 3 71 100 69 1 1 2样例输出 3这其实就是一个简单背包问题的(代码如下) |
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int s[2000]; int j[2000]; int f[2000][2000]; int main() {int t,m; cin>>t>>m; for(int i=1;i<=m;i++) {cin>>s[i]>>j[i];} for(int i=1;i<=m;i++) { for(int v=t;v>0;v--) { if(s[i]<=v) { f[i][v]=max(f[i-1][v],f[i-1][v-s[i]]+j[i]);}// else {f[i][v]=f[i-1][v];} } } cout<<f[m][t]; } |
已知一个数组a[1..........n](n<25)又已知一个整数m。如果能使数组a中任意几个元素纸盒等于吗m,则输出yes,否则输出no. |
f分析:若用函数sum(n,m)表示能从数组中任意取数使其和为m,只要sum(n-1,m-a[n])和sum(n-1,m)当中有一个为真。 |
#include<iostream> using namespace std; int maxl=51; int a[maxl],n,m; bool flag; void sum(int int ); int main() { cin>>n; for9INT I=1;I<=n;i++)cin>>a[i]; cin>>m; flag=false; sum(n,m); if(flag)cout<<"yes"<<endl; else cout<<"no"<<endl; return 0; } void sum(int n,int m) {if(a[n]==m)flag=true; else if(n==1)return;//n=1作为传递边界, else //两种选择。 { sum(n-1,m-a[n]); sum(n-1,m); }} |
一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。如果起点或者终点有一个不能通行(为#),则看成无法办到。输入第1行是测试数据的组数k,后面跟着k组输入。每组测试数据的第1行是一个正整数n (1 <= n <= 100),表示迷宫的规模是n * n的。接下来是一个n * n的矩阵,矩阵中的元素为.或者#。再接下来一行是4个整数ha, la, hb, lb,描述A处在第ha行, 第la列,B处在第hb行, 第lb列。注意到ha, la, hb, lb全部是从0开始计数的。输出k行,每行输出对应一个输入。能办到则输出“YES”,否则输出“NO”。样例输入2 3 .## ..# #.. 0 0 2 2 5 ..... ###.# ..#.. ###.. ...#. 0 0 4 0样例输出 YES NO经典得找路径问题 |
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int dx[5]={0,-1,0,1}, dy[5]={-1,0,1,0}; int a[110][110]; int bo,k,n,f[110][110],ha,la,hb,lb; void dfs(int xx,int yy) { if (bo)return; if (xx==hb&&yy==lb) {bo=1;return;} for(int i=0;i<4;i++) { int x=xx+dx[i],y=yy+dy[i]; if (a[x][y]) { a[x][y]=0; dfs(x,y); } } } int main(){ cin>>k; for (int t=1;t<=k;t++) { cin>>n; memset(a,0,sizeof(a)); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { char ch; cin>>ch; if (ch=='.')a[i][j]=1; } cin>>ha>>la>>hb>>lb; ha++;la++;hb++;lb++; bo=0; if (!a[ha][la]||!a[hb][lb]) {cout<<"NO"<<endl;continue;} a[ha][la]=0; dfs(ha,la); if (bo) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; } |
最后是本人关于递归的一些心得,体会。 |
递归通常把一个大型复杂的问题层层转化为一个与原问题相似的规模的小问题解决,就好比找规律你只要找到了最基本的规律,看似复杂的问,就变得非常容易了。(而往往这个规律,不容易被找到,而递归的难度就在于此)。 |
编写递归函数时,在某些地方要用到if语句,使函数递归到一定程度时,能够返回,然后再层层往前推出最终的结果(回归阶段)。 |
用递归思想编写程序时,会使代码非常简洁,清晰(但也要注意优化,避免超时。) |
用到递归的几种情况 1,问题本身有递归的数学定义,(如,n!,。。。。。) 2,使用递归的数据结构(如扬辉三角。。) 3,问题本身,能分解成相同的子问题。)。 |