递归之初学心得
一, 知识要点
简单的说,递归就是通过一个对象自身的结构来描述或部分描述该对象。
递归定义使人们能够用有限的语句描述一个无穷的集合,就称为递归。
调用自身的语句,称为直接递归调用。也允许被调用的另一个函数又反过来调用原函数,称为间接递归调用。这种功能为递归结构问题提供了求解的实现手段,使程序语言的叙述与问题的自然描述完全一致,因而使程序易于理解、易于维护。
递归调用之所以能够实现,关键是系统使用堆栈来保存函数调用中的传值函数、局部变量和函数调用后的返回地址。函数自身调用进行递推:系统把有关参数和地址压进堆栈,一直递推到满足终止条件,找到问题的最基本模式为止。然后进行回归:系统从堆栈中逐层弹出有关的参数和地址,执行地址所指向的代码,一直到栈空为止,得到问题的解。
递归调用与一般函数带哦用,堆栈管理的操作过程是一致的。不同的是,函数的自身调用就像是产生多个正在运行(等待结束)的相同函数副本。如果这种调用不能终止并产生回归,就是程序十分严重的错误。
递归程序在执行过程中,一般具有如下模式:
①:将调用程序的返回地址、相应的调用前的变量都保存在系统堆栈中;
②:执行被调用的函数
③:若满足退出递归的条件,则退出递归,并从栈顶上弹回返回地址、取回保存起来的变
量值。继续沿着返回地址,向下执行程序:
④:否则继续递归调用,只是递归调用的参数发生变化:增加一个量或减少一个量,重复
执行直到递归调用结束。
二, 疑难问题,以及例题。
首先就是上一篇博客的疑难问题已经被解决
描述
二项式系数C(n, k)因它在组合数学中的重要性而被广泛地研究。二项式系数可以如下递归的定义:
C(1, 0) = C(1,1) = 1;
C(n, 0) = 1对于所有n > 0;
C(n, k) = C(n − 1, k − 1) + C(n− 1, k)对于所有0 < k≤ n。
给出n和k,你要确定C(n, k)的奇偶性。
输入
输入包含多组测试数据。每组测试数据一对整数n和k(0 ≤ k ≤ n < 231),占据独立一行。
文件结束符(EOF)表示输入结束。
输出
对每组测试数据,输出一行,包含一个“0” 或一个“1”,即C(n, k)除以2的余数。
样例输入
1 1
1 0
2 1
样例输出
1
1
0
贴上错误代码
#include<bits/stdc++.h>
usingnamespace std;
int p[10000][10000]={0};
int er(int n,int m)
{
if(p[n][m]>0)return p[n][m];//如果n,m,对应的值在之前求出来过,直接返回已经求出来的值。
if(n==1&&m<=1)return1;
else
if(n>0&&m==0)return1;//判断是否满足条件。
else
return er(n-1,m-1)+er(n-1,m-1);
p[n][m]==er(n,m);//把求出来的存到数组中。
}
int main()
{
int a,b,t;
while(scanf("%d%d",&a,&b)!=EOF)
{
t=er(a,b)%2;
printf("%d\n",t);
}
return0;
}
其实在通过别人的讲解后,发现其实并不需要用递归,如果用递归,二的三十一幂实在是太大了,于是再信息学奥赛一本通上找到了一个简便的符号就能解决这个问题。贴上AC的代码
#include<iostream>
usingnamespace std;
intmain()
{
int n,k;
while(cin>>n>>k)
{
if((n&k)==k)
cout<<1<<endl;
else
cout<<0<<endl;
}
return0;
}
非常简短,就能解决这个比较愁人的问题。
&是按位于运算符:
说明:
把参与运算的两个数对应的二进制位相与,只有对应的二进制均为1时,结果的对应位才为1,否则为0.;
疑难问题
描述
将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O'的最小值。
输入
第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
输出
仅一个数,为O'(四舍五入精确到小数点后三位)。
样例输入
3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3
样例输出
1.633
这道题,实在是没有思路,不知道用递归如何解决。这是在递归里遇到的比较难的题了。也是最没有思路的题,需要再好好沉淀沉淀估计才能想出来吧。
三, 心得体会
通过在递归的做题过程当中,发现递归其实也不难,只要是你找清了如何一步一步计算的,很容易。其实,递归的过程在我看来就是一个数学公式的计算,通过不停的计算就可以寻找到答案。最主要的就是静下心来,一步一步的推,找到如何使用递推,因为有的题也只是部分递推,所以在思考的时候千万不能着急,有的时候觉得没有头绪就慌了,那样的话就更加没有思路了。所以,当我们看到一个递归的题的时候一定要静下心来,即使它很难也不能自己乱了阵脚找张草纸,仔细的推算一遍,就差不多能找出需要的思路,然后将思路列出来,打出代码,稍微修改修改就差不多能得到可以AC程序了。
递归函数很好用,没学递归之前同一道题所写的代码可能时学了递归之后的好几倍,虽然想起来比较复杂,但是代码清晰,易懂。但是要注意反复调用函数这个问题,有的时候堆栈太多,就会出现Runtime error 这种错误,就比如上面的二项式系数。多学多用,才能灵活运用递归,为以后打下坚实基础!!