
一递归概述
递归的核心思想:将大问题分解为相同结构的子问题,直到最小子问题,然后逐步解决。这也是“分治算法”的核心思想。
递归与递推的区别:递推是从已知到未知的过程,递归是从未知到已知的过程;递推是单向的,按照从前往后或者从后往前的单一顺序计算,递归是双向的,先递推下去,再原路回归(也叫“回溯”)。
二递归的实现步骤
- # include <bits/stdc++.h>
- using namespace std;
- // 创建递归函数,计算 n 的阶乘
- int factorial(int n) {
- if (n < 2) return 1; // 确定结束条件(最小子问题的解)
- return n * factorial(n-1); // 根据递推公式计算子问题
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,计算并输出 n 的阶乘
- cout << factorial(n) << endl;
- return 0;
- }
|
|
|
|
|
|
|
|
|
|
- # include <bits/stdc++.h>
- using namespace std;
- // 创建递归函数,计算斐波那契数列第 n 项
- int fib(int n) {
- if (n < 2) return n; // 确定结束条件(最小子问题的解)
- return fib(n-1) + fib(n-2); // 根据递推公式计算子问题
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,计算并输出 n 的阶乘
- cout << fib(n) << endl;
- return 0;
- }
- # include <bits/stdc++.h>
- using namespace std;
- // 创建递归函数,计算到第 n 个台阶的走法
- int slt(int n) {
- if (n < 3) return n; // 确定结束条件(最小子问题的解)
- return slt(n-1) + slt(n-2); // 根据递推公式计算子问题
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,计算并输出到第 n 个台阶的走法
- cout << slt(n) << endl;
- return 0;
- }
-
任取一封信,装错的情况:n-1。 -
在剩余的信中,再任取一封信,装错的情况有两种: 1、与上一封信位置互换,接下来就变成了n-2封信的错排问题; 2、不与上一封信位置互换,接下来就成了n-1封信的错排问题。
-
总结递推式:f(n) = (n-1) * [f(n-1) + f(n-2)]。
- # include <bits/stdc++.h>
- using namespace std;
- // 创建递归函数,计算 n 封信的错排装法
- int cuo_pai(int n) {
- // 确定结束条件(最小子问题的解)
- if (n == 1) return 0;
- if (n == 2) return 1;
- // 根据递推公式计算子问题
- return (n-1) * (cuo_pai(n-1) + cuo_pai(n-2));
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,计算并输出 n 封信的错排装法
- cout << cuo_pai(n) << endl;
- return 0;
- }
- # include <bits/stdc++.h>
- using namespace std;
- // 创建递归函数,倒推计算第 i 施工队面临的任务(n为施工小队数量)
- int dao_tui(int i, int n) {
- // 确定结束条件(当前施工队编号等于施工队数量时,结束递归)
- if (i == n) return n;
- // 根据递推公式计算子问题
- return 2 * dao_tui(i+1, n) + 2 * i;
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,计算并输出第 i 施工队面临的任务
- cout << dao_tui(1, n) << endl;
- return 0;
- }
三求最大公约数
最大公约数(Greatest Common Divisor)是指两个或多个整数公有约数中最大的一个。求最大公约数有多种方法,简略介绍以下三种方法。
- # include <bits/stdc++.h>
- using namespace std;
- // 定义递归函数,使用辗转相除法求最大公约数
- int gcd(int a, int b) {
- if (a % b == 0) return b; // 结束条件
- return gcd(b, a % b); // 更新被除数和除数
- }
- int main() {
- int a, b;
- cin >> a >> b;
- // 确保 a > b
- if (a < b) swap(a, b);
- // 调用递归函数,求a、b两数的最大公约数
- cout << gcd(a, b) << endl;
- return 0;
- }
四分解质因数
-
84 ÷ 2 = 42 → 2
-
42 ÷ 2 = 21 → 2
-
21 ÷ 3 = 7 → 3
-
7 ÷ 7 = 1 → 7
- # include <bits/stdc++.h>
- using namespace std;
- // 定义递归函数,分解质因数
- // n 为待分解数,m 为当前分解出来的数
- void fen_jie(int n, int m) {
- if (n == 1) return; // 结束条件
- if (n%m == 0) {
- cout << m << " ";
- fen_jie(n/m, m); // 递归调用
- } else {
- fen_jie(n, m+1); // 递归调用
- }
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,对 n 分解质因数,从2开始分解
- fen_jie(n, 2);
- return 0;
- }
1、【阅读程序】理解递归函数的执行流程
阅读下列程序,在脑海里预演输出结果,然后再用电脑验证你的猜想。
- # include <bits/stdc++.h>
- using namespace std;
- // 声明递归函数
- void test(int n) {
- if (n > 0){
- test(n-1);
- for (int i=1; i<=n; i++) cout << "*";
- cout << endl;
- }
- return;
- }
- int main() {
- test(5); // 调用递归函数
- return 0;
- }
简单说说上述代码的执行流程,理解递归函数的压栈、出栈过程。
【思考】
如果想得到垂直翻转的图案,该怎么修改上述代码?
2、用递归算法分解质因数
【描述】输入一个正整数n,用递归算法从小到大输出它所有的质因数,以及质因数的总个数。
【输入】一行一个整数n(2<n<10000)。
【输出】第一行为n的质因数,用空格分隔;第二行为质因数的总个数。
【样例输入】24
【样例输出】2 2 2 3
4
【参考代码】用递归算法分解质因数
- # include <bits/stdc++.h>
- using namespace std;
- // 定义递归函数,分解质因数
- // n 为待分解数,m 为当前分解出来的数,cnt为计数器
- void fen_jie(int n, int m, int cnt) {
- if (n == 1) {
- cout << endl << cnt;
- return;
- }
- if (n%m == 0) {
- cout << m << " ";
- cnt++;
- fen_jie(n/m, m, cnt);
- } else {
- fen_jie(n, m+1, cnt);
- }
- }
- int main() {
- int n;
- cin >> n;
- // 调用递归函数,从2开始分解,计数器从0开始
- fen_jie(n, 2, 0);
- return 0;
- }
【思考】
计数器变量cnt能不能在递归函数中声明,而不是通过参数传给递归函数?