「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」
主要思想:从根节点出发,沿着一条线路进行搜索,如果没有节点了,开始回溯直到遇到另一条线路。
注意:节点每一次回溯的时候会观察该节点是否真的其余节点可走了(其余线路),如果没有,则继续回溯,直到找到另外一条线路。
该算法是通过栈数据结构实现的,空间复杂度为O(n),时间复杂度为O(n*n!)。值得一提的是深度优先遍历是靠程序内部的虚拟栈实现,所以不需要再额外定义一个数据结构。回溯的过程也可以把它理解为递归。
模板题目
给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
输入格式
共一行,包含一个整数 n。
输出格式
按字典序输出所有排列方案,每个方案占一行。
数据范围
1≤n≤7
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
思路:
可以把题目抽象成一棵树,逐层遍历树,每一层相当于情况的分支,例如当n=3时,第一层就可以相当于3个数字中的第一位;第二层就可以相当于数字中的第二位;第三层就可以相当于数字中的第三位。然后每一层的每一个节点下面又会有两种情况,当我们逐层遍历完整棵树时,就代表我们已经完成了整个情况的讨论。
代码:
#include<iostream>
using namespace std;
const int N = 10;
int q[N];
bool stk[N];
int n;
void dfs(int u)
{
if(u == n)// 当层数等于n时,代表我们已经遍历到最后一层了,可以进行输出
{
for(int i = 0;i < n;i ++) printf("%d ",q[i]);
puts(" ");
}
for(int i = 1;i <= n;i ++){
if(!stk[i])
{
q[u] = i;
stk[i] = true;// 遍历过的节点,打上标记
dfs(u + 1);
stk[i] = false;// 回溯结束,开始下一种情况讨论,恢复标记
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}