(二十五)递归


更新了!这篇帖子是关于递归的。仔细看,看好了!

(1)递归是什么

递归是有了已知条件,除了已知条件外的所有都可以用一个方法表示出来,这个方法可以自己调用自己,因此叫做递归的方法。所以递归一般会搞成函数

(2)递归怎么解决

  1. 找递归式和边界条件
  2. 理清关系
  3. 编写代码
  4. 修改

(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=fx1×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,看来,众僧们耗尽毕生精力也不可能完成金片的移动。
请添加图片描述
后来,这个传说就演变为汉诺塔游戏:

  1. 有三根杆子A,B,C。A杆上有若干碟子
  2. 每次移动一块碟子,小的只能叠在大的上面
  3. 把所有碟子从A杆全部移到C杆上
    请添加图片描述
    经过研究发现,汉诺塔的破解很简单,就是按照移动规则向一个方向移动金片:  如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C   此外,汉诺塔问题也是程序设计中的经典递归问题。
    算法思路:
  4. 如果只有一个金片,则把该金片从源移动到目标棒,结束。
  5. 如果有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; 
}

预览:

  • 20
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值