分别生成斐波那契数列的第40个元素、第48个元素_L2算法基础第07课 递推

L2-算法基础-第07课 递推

1, 2, 4, 8, 16 …… 数列的下一项是什么? 

1, 2, 3, 5, 8 …… 数列的下一项是什么?

递推

递推就是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果。

可用递推算法求解的问题一般有以下两个特点:

  • 问题可以划分成多个状态;

  • 除初始状态外,其它各个状态都可以用固定的递推关系式来表示.

利用递推算法解决问题,需要做好以下四个方面的工作:

  • 确定递推变量 应用递推算法解决问题,要根据问题的具体实际设置递推变量。递推变量可以是简单变量,也可以是一维或多维数组。从直观角度出发,通常采用一维数组。

  • 建立递推关系 递推关系是指如何从变量的前一些值推出其下一个值,或从变量的后一些值推出其上一个值的公式(或关系)。递推关系是递推的依据,是解决递推问题的关键。有些问题,其递推关系是明确的,大多数实际问题并没有现成的明确的递推关系,需根据问题的具体实际,通过分析和推理,才能确定问题的递推关系。

  • 确定初始(边界)条件 对所确定的递推变量,要根据问题最简单情形的数据确定递推变量的初始(边界)值,这是递推的基础。

  • 对递推过程进行控制 递推过程不能无休止地重复执行下去。递推过程在什么时候结束,满足什么条件结束,这是编写递推算法必须考虑的问题。递推过程的控制通常可分为两种情形:一种是所需的递推次数是确定的值,可以计算出来;另一种是所需的递推次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对递推过程的控制;对于后一种情况,需要进一步分析出用来结束递推过程的条件。

递推通常由循环来实现,一般在循环外确定初始(边界)条件,在循环中实施递推。

递推法从递推方向可分为顺推与倒推。

  • 所谓顺推法是从已知条件出发,通过递推关系逐步推算出要解决的问题的结果的方法。

  • 所谓倒推法,就是在不知初始值的情况下,经某种递推关系而获知了问题的解或目标,从这个解或目标出发,采用倒推手段,一步步地倒推到这个问题的初始情况。

一句话概括:顺推是从条件推出结果,倒推从结果推出条件。

P5743 【深基7.习8】猴子吃桃

题目描述

一只小猴买了若干个桃子。第一天他刚好吃了这些桃子的一半,又贪嘴多吃了一个;接下来的每一天它都会吃剩余的桃子的一半外加一个。第 n(n≤20) 天早上起来一看,只剩下 1 个桃子了。请问小猴买了几个桃子?

输入格式

输出格式

输入输出样例

输入 #1

4

输出 #1

22
分析

倒推来分析, 最后一天是1颗桃子. 第i天的桃子是f[i]的话 第i+1天吃的是i天桃子的一半加1个, 所以剩下的桃子数:f[i+1] = f[i] / 2 - 1

  • 递推公式: f[i] = (f[i+1] + 1 ) * 2;

  • 初始条件: f[n] = 1;

  • 终止条件: i = 1. 循环n-1次.

#include 
using namespace std;

int n, k;

int main(){
cin >> n;
k = 1;
while(n > 1) {
k = 2 * (k + 1);
n--;
}

cout << k;
return 0;
}

常见递推关系

斐波那契数列(兔子数列)

斐波那契数列又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果 。

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

e01da03a2558ffd72a0dddcbd449de76.png幼仔对数=前月成兔对数
成兔对数=前月成兔对数+前月幼仔对数
总体对数=本月成兔对数+本月幼仔对数

递推分析

  • 递推变量: f[n]: 一维数组, 存放兔子对数. 下标表示月份.

  • 初始条件: f[1] = 1; f[2] = 1;

  • 递归公式: f[n] = f[n-1] + f[n-2]

P1255 数楼梯

题目描述

楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。编一个程序,计算共有多少种不同的走法。

输入格式

一个数字,楼梯数。

输出格式

输出走的方式总数。

输入输出样例

输入 #1复制 4 输出 #1复制 5 说明/提示 对于 60% 的数据,N≤50;对于 100% 的数据,N≤5000。

分析
  • 高精 + 斐波那契数列

参考代码
#include <bits/stdc++.h>using namespace std;

int n, a[5006], b[5006], c[5006];
int *f1, *f2, *f3;

void add(int *f1, int *f2, int *f3)
{
int len = max(f1[0], f2[0]);
int x = 0;
for(int i = 1; i <= len; i++) {
f3[i] = f1[i] + f2[i] + x;
x = f3[i] / 10;
f3[i] %= 10;
}

if(x) {
len++;
f3[len] = x;
}
f3[0] = len;
}

int main()
{
scanf("%d", &n);
a[0] = 1;
a[1] = 1;
b[0] = 1;
b[1] = 1;
c[0] = 1;
int * tmp;
f1 = a;
f2 = b; f3 = c;

for(int i = 2; i <= n; i++) {
add(f1, f2, f3);
if(i < n) {
tmp = f1;
f1 = f2;
f2 = f3;
f3 = tmp;
}
}
//printf("%d\n", f3[0]);
if(n == 0)
f3 = c;
else if(n == 1)
f3 = a;

for(int i = f3[0]; i >= 1; i--)
printf("%d", f3[i]);

return 0;
}

卡特兰数

P1044 栈

题目背景

栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。

栈有两种最重要的操作,即 pop(从栈顶弹出一个元素)和 push(将一个元素进栈)。

栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。

题目描述

203e5d0a74c384e574c794bc3f2addba.png

宁宁考虑的是这样一个问题:一个操作数序列,1,2,\ldots ,n1,2,…,n(图示为 1 到 3 的情况),栈 A 的深度大于 nn。

现在可以进行两种操作,

  1. 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)

  2. 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)

使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由 1 2 3 生成序列 2 3 1 的过程。

756a288ef8308aeb7506128fee9e2fbf.png

(原始状态如上图所示)

你的程序将对给定的 n,计算并输出由操作数序列 1, 2, 3, ... ,n 经过操作可能得到的输出序列的总数。

输入格式

输入文件只含一个整数 n(1≤n≤18)。

输出格式

输出文件只有一行,即可能输出序列的总数目。

输入输出样例 输入 #1 3 输出 #1 5

分析
  • 递推变量: f[n] 存放序列的总数目, 下标表示当前队元素个数-也是长度.

  • 递推: f[1] = 1; f[2] = 2, f[3]=5.

  • 递推公式: 假设当前考虑到第i个. 那么前i个元素得到的输出序列有多少个呢? 观察可知, 输出序列的个数和这个序列的元素个数有关. 当i这个元素,出栈时, 已经出栈的个数可能是0, 1, 2, ... i-1个, 剩下的还未出栈. 这些情况不会有重复, 所有总数目是这些情况的和. f[i] = f[0]*f[i-1] + f[1]*f[i-2] + ... + f[i-1]*f[0];

这就是传说中的卡特兰数.

参考代码
#include 
using namespace std;

int n;
long long f[20];

int main(){
scanf("%d", &n);
f[0] = 1;
f[1] = 1;
for(int i = 2; i <= n; i++) {
for(int j = 0; j < i; j++) {
f[i] += f[i-j-1] * f[j];
}
}

printf("%d", f[n]);

return 0;
}

P1002 过河卒

题目描述

棋盘上 A 点有一个过河卒,需要走到目标 B点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A 点 (0,0)、B 点 (n, m),同样马的位置坐标是需要给出的。 ef12f19c3c0a559121eb59ad065effda.png

现在要求你计算出卒从 A 点能够到达 B 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入格式

一行四个正整数,分别表示 B 点坐标和马的坐标。

输出格式

一个整数,表示所有的路径条数。

输入输出样例 输入 #1复制 6 6 3 3 输出 #1复制 6 说明/提示 对于 100% 的数据,1≤n,m ≤20,0 ≤ 马的坐标 ≤20。

分析
  • 递推变量 f[i][j]: 表示走到(i,j)点的路径数. i, j 表示点的坐标.

  • 递推公式: 倒推: 走到(i,j)点只能从(i-1, j)或者(i, j-1)走过来. 这点和数楼梯是一样的. 所以有

f[i][j] = f[i-1][j] + f[i][j-1];
  • 起始条件: f[0][0] = 1;

  • 特殊处理: 马的位置和控制的点, 不能走过去, 所以经过这些点的路径数是0.

f[house_i][house_j] = 0;

参考代码

#include
using namespace std;
unsigned long long chess[26][26];
int ax, ay, bx, by;
int horse[][2]= {
{-2, 1}, {-2, -1}, {2, 1}, {2, -1},
{1, -2}, {1, 2}, {-1, 2}, {-1, -2}
};
int main()
{
int i, j;
scanf("%d %d %d %d", &ax, &ay ,&bx, &by);
ax+=1; ay+=1;
bx+=1; by+=1;
chess[bx][by] = 1;
for(i = 0; i < 8; i++) {
int tbx = bx + horse[i][0];
int tby = by + horse[i][1];
if(tbx < 1 || tby < 1)
continue;
if(tbx > ax || tby > ay)
continue;
chess[tbx][tby] = 1;
}
chess[1][0] = 1;
for(i = 1; i <= ax; i++) {
for(j = 1; j <= ay; j++) {
if(chess[i][j]) {
chess[i][j] = 0;
continue;
}
chess[i][j] = chess[i-1][j] + chess[i][j-1];
}
}
printf("%llu\n", chess[ax][ay]);
return 0;
}

题单

  • P5743 【深基7.习8】猴子吃桃

  • P5534 【XR-3】等差数列

  • P1255 数楼梯

  • P1192 台阶问题

  • P2807 三角形计数

  • P1990 覆盖墙壁

  • P1002 过河卒

  • P1044 栈

  • P1028 数的计算

  • P2437 蜜蜂路线

云帆优培公众号:

092435ad26e9c19ddd73195a84cc93e8.png

云帆优培老师联系方式:

云帆老师

微信:

e95bc5431879e943777719c549266768.png

云帆优培介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值