算法基础3 —— 递归(上)

递归

递归是算法竞赛中的难点。传说人可以理解迭代,但是神才能理解递归。

(不要试图"理解"递归,有很大风险把自己绕进去)

To Iterate is Human, to Recurse, Divine. —L. Peter Deutsch

定义

直接或间接地出现对自身的调用。

本质

递归 = 递进 + 回归
(递进与回归缺一不可)

如何理解递进与回归?
你的面前有一扇门(一号门),打开这扇门,看到屋里面还有一扇门(二号门)。你走过去,发现手中的钥匙还可以打开它,你推开门,发现里面还有一扇门(三号门),你继续打开它… …若干次之后,你打开面前的门后(七号门),发现只有一间屋子,没有门了。然后,你开始原路返回,每走回一间屋子,你数一次,走到入口的时候,你可以回答出你到底用这你把钥匙打开了几扇门。
在这里插入图片描述

基本思想

把规模大的问题转化为规模小的相似的子问题来解决,且必须有一个明确的结束条件即递归出口(例如前例的七号门)

例1

求等差数列1,2,3,4,5,… …的第n项的值

(注:使用递归时需要写出递归表达式,而递归表达式 = 递归关系 + 递归出口)

代码如下:

#include <iostream>

using namespace std;

int f(int  n)
{
    if (n == 1) return 1;//递归出口
    else return f(n - 1) + 1;//递归关系:后一项等于前一项的值加1
}

int main()
{
    int n;
    cin >> n;
    cout << f(n) << endl;
    return 0;
}

同理,如果要求数列1,3,5,7,9,11… …中第n项的值,只需要把递归关系改为return f(n - 1) + 2;即可

递归过程如下所示:(蓝色递进,红色回归)
在这里插入图片描述

例2 Fibonacci数列

1,1,2,3,5,8,13,21… …

#include <iostream>

using namespace std;

int f(int  n)
{
    if (n == 1 || n == 2) return 1;//递归出口
    else return f(n - 1) + f(n - 2);//递归关系
}

int main()
{
    int n;
    cin >> n;
    cout << f(n) << endl;
    return 0;
}

缺点:过多的重叠子问题
优化方法:记忆化

总结:利用递归完成的题目特点
  • 可以将当前问题转换成规模更小的问题,且新问题和原问题解法完全相同
  • 有一个明确的递归边界

在这里插入图片描述

例3 :用递归方法求:1+2+3+……+n

(本题为中国矿业大学2021年考研初试题,很多同学以往用for循环完成本题,而疏于锻炼递归思想)

代码如下

#include <iostream>

using namespace std;

//Sum(n)表示数列前n项的和
int Sum(int  n)
{
    if (n == 1) return 1;//递归出口
    else return Sum(n - 1) + n;//递归关系:前n项的和=前n-1项的和+n
}

int main()
{
    int n;
    cin >> n;
    cout << Sum(n) << endl;
    return 0;
}
例4 : 用递归方法求n!
#include <iostream>

using namespace std;

int f(int  n)
{
    if (n == 1) return 1;//递归出口
    else return f(n - 1) * n;//递归关系
}

int main()
{
    int n;
    cin >> n;
    cout << f(n) << endl;
    return 0;
}
例5 : 王小二切饼

原题链接

有一张大的煎饼在砧板上,饼不许离开砧板,切n(1<=n<=100)刀最多能将饼分成几块?

输入格式:输入切的刀数n

输出格式:输出切n刀最多切的块数

输入样例:3

输出样例:7

分析:
如图所示,切1刀最多可以将饼分成2块:
在这里插入图片描述

切2刀最多可以将饼分成4块:
在这里插入图片描述
切3刀最多可以将饼分成7块:
在这里插入图片描述
切4刀最多可以将饼分成11块:
在这里插入图片描述
不难发现:

  • 要想将饼的块数切的较多,需要满足切割线两两相交且没有交点
  • 第1刀 —— 2块;
  • 第2刀 —— 4块;(2 + 2)
  • 第3刀 —— 7块;(3 + 4)
  • 第4刀 —— 11块;(4 + 7)
  • … …
  • 设第n-1刀 —— i块
  • 则第n刀 ——(n+i)块

设切第n刀可以得到f(n)块饼,由此得到递归表达式:

if (n == 1) return 2;
else return f(n - 1) + n;

代码如下:

#include <iostream>

using namespace std;

int f(int  n)
{
    if (n == 1) return 2;//递归出口
    else return f(n - 1) + n;//递归关系
}

int main()
{
    int n;
    cin >> n;
    cout << f(n) << endl;
    return 0;
}
今日冷笑话

—— “你买的什么书?”
—— “编程”
—— “C++还是java”
—— ”沈从文“

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值