什么是递归
递归(Recursion)是一种编程技术,指的是一个函数在其定义过程中调用自身的现象。递归通常用来解决可以被分解为多个相似的小规模子问题的问题。
递归函数一般由以下几部分组成:
-
基准条件:递归结束的条件,也称为终止条件,防止函数无限调用自己。通常是简单情形或最小规模的问题,直接返回结果。
-
递归步骤:在函数内部调用自己,将问题逐步缩小,朝着基准条件的方向前进。每次调用递归函数时,都会将问题规模减小(如参数递减或数据量减小),直至达到基准条件。
九连环问题
L2-1【用递归实现】 九连环问题
九连环是一种流传于山西省的传统民间的智力玩具,由九个圆环相连成串,以解开为胜。
九连环的九个环,一环扣一环地套在钗上。除了第 1 号环可以随时装上或卸下以外,其它环装上或卸下的条件是:在它的前面仅有紧靠它那一个环在钗上。即:当第 1 ~ i−2 号环都不在钗上,第 i−1 号环在钗上,这时可以装上或卸下第 i 号环。
输入格式
环数 操作(U表示装上, D表示卸下)
输出格式
装上或卸下九连环的操作步骤
每行显示一步操作,具体格式为:
环号: U或D (U表示装上,D表示卸下)
输入样例1
3 U
输出样例1
1: U
2: U
1: D
3: U
1: U
输入样例2
4 D
输出样例2
2: D
1: D
4: D
1: U
2: U
1: D
3: D
1: U
2: D
1: D
九连环问题的递归解决
那么,对于九连环问题,我们用递归的方式解决这类问题,其中手动分析是一个重要的阶段,只有正确的用手算找到其中的规律,才能用机器代码的方式表述出来
九连环的游戏规则:
(1)第 1 环可以自由上下;
(2)而上/下第 n 环时(n>1),则必须满足:(a)第 n-1 个环在架上;(b)前 n-2 个环全部在架下。
为了更好地理解,我们可以通过一个稍微复杂的例子来分析装第 5 号环的过程。
要上第5环,第4环必须在前面,且321都不能在上面
所以,要上前5环,需要分为这四个步骤
前四环上去,前三环下来,这样才能把第五环装上,再把前三环上来
对于这四个步骤,还能继续分,
前四个上去可以拆分成,前三个上去,前两个下来,第四个上去,前两个上来
不要怕麻烦,跟着我的文字描述自己写一遍你就会了,总结就是:我们要完成前 5 个环的上环操作,可以分成以下几个步骤:
- 上前四环:首先上前四个环。
- 下前三环:然后将前三个环卸下。
- 装上第 5 个环。
- 将前三环重新装上。
这样,我们就把一个大问题拆解成了若干小问题,类似“爬楼梯”一样,逐步接近目标。✧(≖ ◡ ≖✿)
对于下环来说,除了最后两步需要单独描述,其余的步骤都是有规律的,所以我们把最后两步当作我们的递归出口
我们再用机器能看懂的语言来描述一下“下环”这个函数
void D(int n){
if(n>2){
D(n-2);
cout<<n<<": "<<"D"<<endl;
U(n-2);
D(n-1);
}
if(n==2){
cout<<2<<": "<<"D"<<endl;
cout<<1<<": "<<"D"<<endl;
}
if(n==1){
cout<<1<<": "<<"D"<<endl;
}
}
那么上环也是同样的,大家手写一遍就明白了,代码如下
void U(int n){
if(n>2){
U(n-1);
D(n-2);
cout<<n<<" "<<"U"<<endl;
U(n-2);
}
if(n==2){
cout<<1<<" "<<"U"<<endl;
cout<<2<<" "<<"U"<<endl;
}
if(n==1){
cout<<1<<" "<<"U"<<endl;
}
}
递归解题的要点
- 找出规律:每个步骤按照规则递归地调用自身。
- 设定出口:当问题简化到最小规模(例如
n==1
或n==2
)时,直接输出,不再递归。
运行结果: