========================================================================================================
不好意思兄弟们,图片挂了,最近比较忙没能重新弄一下,可以参考我的CSDN博客[AcWing]842. 排列数字(C++实现)dfs模板题,递归思想的解释,与此篇题解是相同的。
========================================================================================================
递归的难度在于理解递归是如何回退的。
1. 题目
2. 读题(需要重点注意的东西)
思路:
---------------------------------------------------dfs的思想---------------------------------------------------
dfs深度优先遍历的思想比较简单,就是一条路走到底,走到最深点处再回退一步,再看有没有路可以走,没有的话再回退一步,重复此步骤;
dfs的思想比较简单,在此不在过多的赘述,解释代码中实现dfs的递归方法,是本文的主要目的。
---------------------------------------------------递归的思想---------------------------------------------------
递归在于不断调用自己的函数,层层深入,直到遇到递归终止条件后层层回溯,其思想与dfs的思想不谋而合;因此,可以使用递归来实现dfs。
递归的进入比较容易理解,但是递归的回溯是在计算机底层执行的,我们无法看到。因此,递归究竟是如何完成的,成为了理解递归的一大难点,也是理解递归的唯一一个难点。
让我们来看一下这样一个简单的递归程序
#include<iostream>
using namespace std;
int n;
void func(int u){
if(u == 0) return;
cout << "Recursive program goes to the next level --- " << u << endl;
func(u-1);
cout << "Recursive program backtracking --- " << u <<endl;
return;
}
int main(){
cin >> n;
func(n);
return 0;
}
输入3,我们可以看到,它的输出是
我们可以清楚的看到,哪个数字进入了递归,又有哪个数字回溯了。
为什么会产生这样的结果?请看下面这幅图,它解释了递归函数的调用全过程
这样,我们就能理解,为什么首先输出的是Recursive program backtracking — 1了
如果还不是很理解,请看下面的图,我们从u = 0 回退到了u = 1,再直接回退到u = 2,再回退到u = 3
递归程序在回退完成前,return会使得计算机继续依次执行上一层函数调用后的代码。
3. 解法
---------------------------------------------------解法---------------------------------------------------
#include <iostream>
using namespace std;
const int N = 10;
int n;
int path[N]; // 用path数组保存路径上的值
void dfs(int u, int state)
{
if (u == n) // 处理完叶子节点
{
for (int i = 0; i < n; i ++ ) printf("%d ", path[i]); // 输出路径上的值
puts(""); // 换行
return;
}
// 在每一层选取没有被用过的数,然后进入下一层
for (int i = 0; i < n; i ++ )
if (!(state >> i & 1)) // 选择一个没有被用过的值放在path[u]中
{
path[u] = i + 1;
dfs(u + 1, state + (1 << i)); // 进入下一层
}
}
int main()
{
scanf("%d", &n);
dfs(0, 0);
return 0;
}
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
6. 总结
dfs模板题,推荐完全背下来。递归的思想也要好好的理解并掌握。
其实调用函数相当于入栈,函数结束就出栈
是的hhh
不好意思兄弟们,图片挂了,最近比较忙没能重新弄一下,可以参考我的CSDN博客[AcWing]842. 排列数字(C++实现)dfs模板题,递归思想的解释,与此篇题解是相同的
先递到头再归
有没有知道 u在递归过程中是怎么变化的? u+1 不是影响了 u 原来等于 1的值吗?那么第一层1开头的递归结束后输出123和132之后 接着第二层i=2开始递归,输出213,231 的过程中 进入for循环 u怎么还能从1开始?
图片失效了,有人保存了图片吗
我保存了
但是就一张
已经理解了,谢谢!
#太秀了
感谢大佬,感觉学到许多!
%%%
背下来有什么好处吗?
同学,倒数第二张图片画错了吧?就是解释递归函数的调用全过程那张,输出答案的应该是触发终止条件的框框啊(就是第 $4$ 个框框),触发了判断条件先输出才是返回吧。
他这个图里的输入输出应该指的是递归函数的输入和输出,对于这道题而言,我们确实是在处理完叶节点后就输出了方案,但是递归函数里最终还是回溯到最外层。
哦对
给朋友提一点点微不足道的不成熟的小建议,第12行的if(u == n) 注释应该是“处理完所有叶子结点时”,而不是“到达叶子结点时”。
是的hhh,确实会有歧义,谢谢,已经修改~
这个递归机制真的帮助到我了,之前看了一些递归机制都不太清楚吧
Orz
tql
大神膜拜,tql!!!!!!!!!!!!!!!!!!!!!
大佬 膜拜
Orz