更新了!这篇帖子是关于递归的。仔细看,看好了!
(1)递归是什么
递归是有了已知条件,除了已知条件外的所有都可以用一个方法表示出来,这个方法可以自己调用自己,因此叫做递归的方法。所以递归一般会搞成函数
(2)递归怎么解决
- 找递归式和边界条件
- 理清关系
- 编写代码
- 修改
(3)例题
1. 强哥到底有多强
https://oj.joyskid.cn/problem.php?id=3438
题目描述
众所周知,强哥是真的很强,但是到底有多强呢?
一般来说,一个人实力越强战斗值越高,战斗值保证是一个整数。有十个同学在讨论这个问题,第十个同学说强哥的战斗值和他相当。第九个同学说第十个同学的战斗值是他的5倍还高1分,第八个同学说第九个同学的战斗值是他的5倍还高1分,第七个同学说第八个同学的战斗值是他的5倍还高1分,依次类推……直到第一个学生,第一个学生的战斗值是-1分。
害羞的强哥藏起了答案,聪明的你能算出他的战斗值吗?
输入 无
输出 输出一个整数,表示强哥的战斗值
这道题如何解决呢?以上涂了黄色背景的是重点。其中“是他的5倍还高1分”转换成递归式为上一个同学的战斗值=这个同学的战斗值×5+1
,起始条件是-1
。假如
f
x
f_{x}
fx表示第
x
x
x同学的战斗值,那么递归式为:
f
x
=
f
x
−
1
×
5
+
1
(
f
1
=
−
1
)
f_{x}=f_{x-1}\times5+1 (f_{1}=-1)
fx=fx−1×5+1(f1=−1)
递归因为会自己调用自己,因此要封装为函数
int f(int n) {
if(n==1) return -1;
else return f(n-1)*5+1;
}
最终在main()
函数中调用函数就成功了
int main() {
cout << f(10);
return 0;
}
题解
#include <bits/stdc++.h>
using namespace std;
int f(int n) {
if(n==1) return -1;
else return f(n-1)*5+1;
}
int main() {
cout << f(10);
return 0;
}
2. 过河卒
这是一道特殊的递归题,涉及到回溯算法
题目描述
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,且C≠A,C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。
输入 给出n、m和C点的坐标。
输出 从A点能够到达B点的路径的条数。
样例输入
8 6 0 4
样例输出
1617
这里我们可以把回溯理解为分身卒。首先,第一个卒在(1,1)的位置,他先创建了一个分身卒在(2,1),接下来判断分身卒有没有越界、到马的攻击点或到马的位置,如果判断为真,那么这个卒不能要了,就回收并判断(1,2),否则在(2,1)创建分身卒(3,1),再次判断。直到最终分身卒到达了终点,就回到上一个分身卒那里看看有没有能走的点,没有再回去,又回去,又双叒叕回去,直到哪里都走不了了,就算结束了。
“马”下过象棋的都知道走日字格,可以看作走在(x+1,y+2), (x+2,y+1), (x-2,y-1), (x-1,y-2), (x+1, y-2), (x+2, y-1), (x-1, y+2), (x-2, y+1)的位置,这里还规定“卒”不能吃“马”,因此还要加上(x, y)的位置。
题解
#include <bits/stdc++.h>
using namespace std;
int n, m, x, y, cnt=0;
void f(int __x, int __y) {
if(__x==x&&__y==y) {//到达终点
cnt ++;
} else if(__x>x||__y>y|| //越界
__x==n&&__y==m ||
__x==n+1&&__y==m+2 || __x==n+2&&__y==m+1 ||
__x==n-1&&__y==m-2 || __x==n-2&&__y==m-1 ||
__x==n-1&&__y==m+2 || __x==n+1&&__y==m-2 ||
__x==n+2&&__y==m-1 || __x==n-2&&__y==m+1 //九个控制点
) {
return;
} else {
f(__x+1, __y); //卒向右走
f(__x, __y+1); //卒向下走
}
}
int main() {
ios::sync_with_stdio(false); //IO加速代码
cin.tie(0);
cin >> x >> y >> n >> m;
f(0, 0); //从左上角开始遍历
cout << cnt; //输出
return 0;
}
3. 汉诺塔步骤分析
汉诺塔(Hanoi Tower)也是一道经典问题
题目描述
汉诺塔(又称河内塔)问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。面对庞大的数字(移动圆片的次数)18446744073709551615,看来,众僧们耗尽毕生精力也不可能完成金片的移动。
后来,这个传说就演变为汉诺塔游戏:
- 有三根杆子A,B,C。A杆上有若干碟子
- 每次移动一块碟子,小的只能叠在大的上面
- 把所有碟子从A杆全部移到C杆上
经过研究发现,汉诺塔的破解很简单,就是按照移动规则向一个方向移动金片: 如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C 此外,汉诺塔问题也是程序设计中的经典递归问题。
算法思路: - 如果只有一个金片,则把该金片从源移动到目标棒,结束。
- 如果有n个金片,则把前n-1个金片移动到辅助的棒,然后把自己移动到目标棒,最后再把前n-1个移动到目标棒。
输入
一个整数N,表示A柱上有N个碟子。(0<n<=10)
输出
若干行,即移动的最少步骤
样例输入
3
样例输出
A To C
A To B
C To B
A To C
B To A
B To C
A To C
题解
#include <iostream>
using namespace std;
void hanoi(int n, char a, char b, char c) {
if(n==0) return; //如果柱子都到C柱了,就停止函数运行
hanoi(n-1, a, c, b); //交换b和c
cout << a << " To " << c << '\n';
hanoi(n-1, b, a, c); //交换a和b
}
int main() {
int n;
cin >> n;
hanoi(n, 'A', 'B', 'C'); //运行
return 0;
}
预览: