#创作计划# 递推算法精讲|普及组算法
2025-12-13 21:38:13
发布于:江西
例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
Gold King上色 青青草原上有一个神秘的地方,叫做女娲谷。谷里有一排排长度不一的石格子,相传是女娲补天之后留下来的,并且还有一个传说一起流传下来,如果能用三种颜色把格子都填色,就能得到女娲的祝福。青青草原的人每年都派人去尝试,今年轮到 GoldKing,GoldKing也为了锻炼自己,背着三包颜料就出发了。
刚进入谷口,就有一行若隐若现的文字显示出来:“用三种颜色对一行格子涂色,要求相邻两个格子的颜色不同并且头尾的颜色也不同,这里注意只有一个格子的时候,既是头也是尾。”,这里GoldKing有一个疑惑如果当格子数为n时,有多少种不同的涂法呢,需要你帮忙解决一下?
定义初始状态
题目说了,1个格子和0个格子的填法数都为0,但这道题光有这两个条件还不够。顺着往下想,当有2个格子时,第一格就是头,第二格就是尾,根据题意,这两个格子的颜色应该互不相同。从3种颜色中选2种颜色组合在一起,有红绿、红黄、绿红、绿黄、黄红、黄绿六种方案。用表示有个格子时的填法数,则。
找到递推关系式
当有3个格子时,第一个格子是头,第三个格子是尾,第三个格子既不能和第一个格子相同,也不能和与它相邻的第二个格子相同,那第三个格子只有除去前两个格子的剩下的一种颜色可填。所以2个格子的填法数是6,3个格子的填法数也是6。
当有4个格子时,要考虑2种情况。第一种情况,是直接在符合要求的3个格子之后加上一个格子。第一个格子是头,第四个格子是尾,第四个格子既不能和第一个格子相同,也不能和与它相邻的第三个格子相同,那第四个格子只有除去第一个格子和第三个格子的剩下一种颜色可填,则4个格子的填法数和3个格子一样,也是6。关系式为:
第二种情况,因为增加到4格后,第三格已经不是尾了,可以和第一格相同。第四个格子仍然既不能和第一个格子相同,也不能和与它相邻的第三个格子相同,但第一格和第三格实际上是同一种颜色,所以第四格可以填除去这一种颜色的其余两种颜色。而第一格确定了,第三格就不用考虑了,全部4格的填法数只跟去掉第三格的前2格有关,并且是前2格填法数的2倍。关系式为:
最终的填法数就是这两种情况的填法数之和,递推关系式:
完整代码
#include <iostream>
using namespace std;
long long a[60];
int main() {
a[0] = 0, a[1] = 0, a[2] = 6;
int n;
cin >> n;
for (int i = 3; i <= n; i++) {
a[i] = a[i - 1] + a[i - 2] * 2;
}
cout << a[n];
return 0;
}
那么本帖就到这里结束了,谢谢各位的观看
如有错误,欢迎指正~
点个赞吧
@AC君 求加精
全部评论 5
最好不要用黄色字体,不然很难加精
2025-10-12 来自 浙江
1等我全部写完再加
#创作计划#2025-10-18 来自 江西
0好
2025-10-18 来自 浙江
0但是
2025-10-18 来自 浙江
0
不管了催更!!!!!!!
2025-11-07 来自 浙江
0对了,格式上注意一下
2025-10-26 来自 浙江
0?
2025-11-08 来自 江西
0
这次三级考了结构体中的结构体
2025-10-20 来自 福建
0我是一个农村人
2025-10-19 来自 浙江
02025-10-19 来自 浙江
0














有帮助,赞一个