递推算法精讲|普及组算法(未完)
2025-10-18 17:21:43
发布于:江西
例1
上台阶
有级的台阶,你一开始在底部,每次可以向上迈最多级台阶(最少级),问到达第级台阶有多少种不同方式。
审题
一开始在第0层,每次要么跨1层,要么跨2层,利用加法原理:
- 到第1层有1种方法:跨1层;
- 到第2层有2种方法:一层一层走&直接跨两层;
这2个条件是我们预先知道的,后续的就很容易计算出来了。在走到第3层之前有2种情况,第一种情况我们是从第1层跨两层上来的,第二种情况我们是从第2层跨一层上来的。也就是说,求走到第3层的方式数就是求走到第1层和第2层的方式数之和。如果用记录走到第层的方式数,那么计算第3层方式数的算式就是:
其实,也可以这样说:走到第3层的方式数是前两层的方式数之和。那么肯定不光第三层可以这样算,第4层和第5层应该也可以,第10层可以……这个楼梯的任意一层都可以这样算。如果想计算第层呢?也是这个方法,第层的方式数就是第层和第层的方式数之和。可以用以下算式表示:
因为每一项都依赖它的前2项,所以算的时候要自底向上计算:从第3层开始一直这样算到第层。看到这停一下,请先把上面的内容消化消化。
如果你完全理解了上面的内容,不难写出以下代码:
#include <iostream>
using namespace std;
int main() {
int n;
long long a[10005];
cin >> n;
a[1] = 1, a[2] = 2; // 预先知道的条件
for (int i = 3; i <= n; i++) {
a[i] = a[i - 1] + a[i - 2]; // 逐层计算每一层的方式数
}
cout << a[n];
return 0;
}
递推的基本思想
在上一题中,我们使用了一种新算法,这种算法叫做递推法,它的基本思想是利用已经计算出的结果来推导新的结果,从而避免重复计算,提高效率。递推法有正推和反推两种形式:
- 正推就是从前向后递推,已知小规模问题的解递推到大规模问题的解;
- 反推就是从后向前递推,已知大规模问题的解递推到小规模问题的解。
解决递推问题的步骤
解决递推问题的步骤如下:
1.定义初始状态
我们把递推过程中计算出的每一项称为一个状态,通常初始状态是题目中已经告诉我们的或是我们自己根据题干很容易推导出的一个量,后续的所有计算都是建立在初始状态的基础之上的。例如,在“上台阶”中,初始状态是第一层和第二层的方式数,这两个值是我们根据逻辑直接得到的,而不是用式子计算出来的。
找到了初始状态,再对它们进行定义。
2.找到递推关系式
要做好递推,这一步非常关键。递推关系式就是找出未知状态和已知状态之间的关系,并用一个宽泛的数学式子来表示这种关系。这个关系式应该对于任意一个状态都有效。
在例题1中,这种关系是“每一层的方式数就是前2层的方式数之和”,因此递推关系式就是。
例2
填数 在n个格子内填数,每个格子内只能填1,2,3中的一个,要求任意相邻的两个格子内的和为偶数,请你求出n个格子的时候有几种填法。
定义初始状态
先找初始状态,初始状态题目中的样例已经告诉我们了,即只有2个格子时的填法数。如果用来记录当有个格子时的填法数,那么。
找到递推关系式
在你找出了和为偶数的组合情况有1+3,3+1,1+1,3+3,2+2这5种以后,不难发现:如果前面的格子是填奇数,那么奇数后面还是奇数,有1或3这两种情况,则前个格子的填法数是前个格子的2倍。递推关系式为:
如果考虑偶数情况(只有1种情况,因为2后面只能填2),那么乘以2之前要把偶数的一种情况去掉,乘完了以后再加上这一种情况。递推关系式:
完整代码
#include <iostream>
using namespace std;
long long a[10005];
int main() {
int n;
cin >> n;
a[2] = 5; // 初始状态
for (int i = 3; i <= n; i++) {
a[i] = (a[i - 1] - 1) * 2 + 1; // 递推关系式
}
cout << a[n];
return 0;
}
全部评论 3
最好不要用黄色字体,不然很难加精
1周前 来自 浙江
1等我全部写完再加
#创作计划#
5天前 来自 江西
0好
4天前 来自 浙江
0但是
4天前 来自 浙江
0
这次三级考了结构体中的结构体
3天前 来自 福建
0我是一个农村人
4天前 来自 浙江
04天前 来自 浙江
0
有帮助,赞一个