浅浅的谈一下递归(蓝桥杯)

1|0从蓝桥杯的角度看看递归

依托具体题目,AC代码及其题解,谈谈我对递归的理解

1|1题目1

从 1∼n1∼n 这 nn 个整数中随机选取任意多个,输出所有可能的选择方案。

1|0输入格式

输入一个整数 nn。

1|0输出格式

每行输出一种方案。

同一行内的数必须升序排列,相邻两个数用恰好 11 个空格隔开。

对于没有选任何数的方案,输出空行。

本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。

1|0数据范围

1≤n≤151≤n≤15

1|0输入样例:

3

1|0输出样例:

3
2
2 3
1
1 3
1 2
1 2 3

1|2题解1

1|0AC代码

#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 16;
int st[N];
void dfs(int u) {
if (u > n) {
for (int i = 1; i <= n; ++i) {
if (st[i] == 1) {
cout << i << ' ';
}
}
cout << endl;
return ;
}
st[u] = 1;
dfs(u + 1);
st[u] = 0;
st[u] = 2;
dfs(u + 1);
st[u] = 0;
}
int main() {
cin >> n;
dfs(1);
return 0;
}

1|0问题

  1. 数据范围是(1 <= 15)在设定上限的时候为什么设定为 16
  2. 搞不懂递归
  3. 为什么在 18行 后面要把 st[u] 还原

1|0解释

  1. 因为里面的有效数据是从 1 开始的,你也可以尝试着从 0 开始

  2. 递归的定义中,自己调用自己,并不准确,自己调用自己一定是死递归,而我们的递归之所以会自动停下,是因为,每次递归调用的时候,函数本身已经向我们的理想状态偏移了。

    另外,看不懂递归大约是因为不肯动手去画递归树。

    当你看不懂一个程序的时候,你最好拿最简单的数据,严格按照电脑的执行方式去执行一次(我们现在也可以运用调试功能,但是我还是觉得手动更好)

  3. 能执行 19 行代表 18 行语句执行完毕,所以要把数据恢复,便于下一次的调用

    在这里面:

    st[i] == 0 代表 i 数据暂未考虑

    st[i] == 1 代表 i 数据选

    st[i] == 2 代表 i 数据不选

1|0可视化的展示

假设此时输入的 n 为 3

u =1 u>n ? × st[1] = 1 dfs(1+1)
u = 2 u>n ? × st[2] = 1 dfs(2+1)
u = 3 u>n ? × st[3] = 1 dfs(3+1)
u = 4 u>n? √ ==> 循环输出已有的结果 st[3] = 0 && st[3] = 2 dfs(3+1)
u = 4 u>n? √ ==> 循环输出已有的结果 st[3] = 0 return;返回上一层

其实这个,是谁写谁知道!手工写一下,比苦思半天更有效果!

1|3题目2

把 1∼n1∼n 这 nn 个整数排成一行后随机打乱顺序,输出所有可能的次序。

1|0输入格式

一个整数 nn。

1|0输出格式

按照从小到大的顺序输出所有方案,每行 11 个。

首先,同一行相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。

1|0数据范围

1≤n≤91≤n≤9

1|0输入样例:

3

1|0输出样例:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

1|4题解2

1|0AC代码

#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 10;
int st[N];
bool used[N];
void dfs(int u) {
if (u > n) {
for (int i = 1; i <= n; ++i) {
cout << st[i] << ' ';
}
cout << endl;
return ;
}
for (int i = 1; i <= n; ++i) {
if (!used[i]) {
used[i] = true;
st[u] = i;
dfs(u + 1);
st[u] = 0;
used[i] = false;
}
}
}
int main() {
cin >> n;
dfs(1);
return 0;
}

1|0问题

  1. st[] 和 used[] 分别代表什么
  2. 这道题和上面那道题有什么区别吗?
  3. 递归搞不懂

1|0解释

  1. st[] 数组表示目前排列的数据,used[] 表示该数字是否用

  2. 大方向上都是深度优先搜索,并没有什么区别,细分的化就是代码实现上不同了。

  3. 亲,自己动手模拟一下比我讲半天都有用。

    还是那句话,谁亲自动手写了谁就一定会

1|0可视化展示

还是以 n = 3 进行演示

u = 1 u > n ? × used[1] = false ? √ used[1] = true st[1] = 1 dfs(1+1)
u = 2 u > n ? × used[1] = false ? × ==> used[2] == false ? √ used[2] = true str[2] = 2 dfs(2+1)
u = 3 u > n ?× used[1] ……used[3] == false? √ used[3] = true str[3] = 3 dfs(3+1)
u = 4 u > n ? √ 对结果进行输出 st[3] = 0 usde[3] = false ……

我承认这个展示确实不算太完整,但是相信用心的人还是能看懂

另附上代码的运行结果

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

1|5小结

  1. 在写递归函数的时候,我们总是爱把递归的出口放在函数的头部
  2. 递归代码的缺点是难以理解,优点是简短
  3. 套用上面两个dfs(深度优先)的递归算法,可以帮助我们更丝滑的刷题。

__EOF__

本文作者userName
本文链接https://www.cnblogs.com/codezzzsleep/articles/16073872.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   codezzzsleep  阅读(47)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示