超级经典的回溯算法,必须会
题目简述
给定一个整数n,将数字1~n排成一排,按照字典序将所有的排列输出。
输入格式
共一行,包含一个整数n。
输出格式
按字典序输出所有排列方案,每个方案占一行。
数据范围
1≤n≤9
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
暴力枚举
上图是递归树。我们要枚举,递归都可以画一棵树。当我们到最后一层时候,即该排列所有位都枚举完,填上数字了,就输出并返回。否则我们要枚举该排列的枚举的位上应该填什么数。
经典的回溯算法,暴力枚举。 时间复杂度O(N!),空间复杂度O(N),用一个数组来存储每次枚举的状态
核心代码
#include <iostream>
using namespace std;
const int N = 10 ;
int n;
bool st[N];//记录该点是否已经用过了,用于剪枝
int path[N];
void dfs(int u){
if (u == n){
//到最后一层,所有位都填好了
for (int i = 0 ; i < n ; i ++) cout << path[i] << " ";
cout << endl;
return ;
}
//还没到最后一层,枚举该位置能放哪些数
for (int i = 1 ; i <= n ; i ++){
//剪枝
if (st[i] == false){
path[u] = i;
st[i] = true;
dfs(u + 1);//递归下一层
st[i] = false;//回溯的恢复
}
}
}
int main(){
cin >> n;
//暴力枚举
dfs(0);
return 0;
}