n个星期前:
所以说在被递归暴力的狠狠的虐了之后,我终于也可以虐递归啦(不存在的),于是怀着对汉诺塔的敬意和对递归的迷茫敲下了这篇总结,请记住:万物皆虚,万世皆允(划掉)。
最初开始看递归的时候,我是被逼得想从9楼信仰之跃的(虽然我那会还没开始玩刺客信条……),总之就是很懵,现在还好。
PS:
n个月后,我又回来完善了!感觉自己似乎是想通了递归,就算不对也不要告诉我!
我们还记得递归存在爆栈这种说法,我们就把递归的过程想象成一个栈,每次数要入栈时,都要经过递归函数的运算,当满足返回条件时,就是出栈,然后返回到上一个栈的位置中未完成的计算接着进行下一个栈顶元素的入栈计算,这也就是为什么递归每一层存的数互不干扰,因为这本身就是一个栈,每一个数在栈中不同的位置上,同样这也是为何递归返回时必须从最后一层一层的返回,因为栈是先进后出的,就像垒成一摞的盘子,要想取走最底层然后结束递归,必须把以上所有盘子取走。只不过递归使用的是系统栈,不需要手动模拟出一个栈
总之递归就是一种调用自身进行运算的骚操作,当然,我们用数学函数一种类似的做法来表示以方便理解,f(f(f(f(f(x-2))))),那么从这个函数我们可以看出来,这是一种将大问题向下化为小问题,在通过小问题逆向推导出大问题的做法,以这个函数举例,要想求出最终解,首先要求出x-2,然后一层一层进行运算,当然,递归与这种函数具有很大的差距。
递归的一般形式就不打了,来谈谈递归的运行,大量的内容在书上已经很是详尽了,所以我们用具体题目来理解递归:
那么这道题是一道不算难的题目,其主要思想在于分情况讨论,然后就是,纯递归会因为运行过慢爆掉,所以我们用空间换时间的思想,用记忆化搜索解决
代码如下:
1 #include <iostream> 2 #include <iomanip> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #include <cstdio> 7 using namespace std; 8 int n,m; 9 int ans=0; 10 int f[50][50]; 11 int cq(int k,int x)//k次传,x个小学生 12 { 13 if(f[k][x]>=0) return f[k][x]; 14 if(k==m)//边界,如果传球次数达到m,结束递归 15 { 16 if(x==1) 17 return 1; 18 return 0; 19 } 20 if(x==n) //特判,当传到第n个人手里时 21 { 22 f[k][x]=cq(k+1,n-1)+cq(k+1,1); 23 } 24 else 25 if(x==1) //特判,当传到第1个手里时 26 { 27 f[k][x]=cq(k+1,n)+cq(k+1,2); 28 } 29 else //正常传球方式 30 { 31 f[k][x]=cq(k+1,x+1)+cq(k+1,x-1); 32 } 33 return f[k][x]; 34 } 35 int main() 36 { 37 cin>>n>>m; 38 memset(f,-1,sizeof(f)); 39 f[m][1]=1; 40 cout<<cq(0,1); 41 return 0; 42 }
从这道题,我们就可以较为清楚了理解递归的基础思维,至于更深层次的?自己翻dalao的博客去,你们不能指望我一个蒟蒻写什么高深的东西。
现在:
很好,我已经深刻认识到递归到底有多么难懂了。在noip初赛被手动递归狠狠地,暴力地,完美地虐杀掉之后,我就觉得我怕不是根本学不动递归。。???若是说每一个递归都能用递推写过还好,但是实际并不能,所以说这就很蒙,怕不是noip复赛要崩盘?????心态炸裂
咔咔咔....
上古文章懒得整理了...就这样吧 ——9102年2.12