【ETOJ P1016】全排列 题解(深度优先搜索+位集合+回溯算法)

题目描述

给定一个数字 n n n,请按照字典序输出排列 [ 1 , 2 , . . . , n ] [1,2,...,n] [1,2,...,n] 的全排列。

输入格式

一个整数 n n n ( 1 ≤ n ≤ 9 ) (1 \le n \le 9) (1n9)

输出格式

一行输出一个结果,按照字典序从小到大排列。

样例输入1

3

样例输出1

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

思路

定义一个位图(bitset)vis来记录哪些数字已经被使用过,以及一个数组a来存储当前的排列。这两者都是全局变量,可以在整个程序中访问。

然后,我们在main函数中获取用户输入的数字n,这个数字表示我们要生成多少个元素的全排列。vis.reset()是将所有位设置为0,表示一开始所有的数字都没有被使用过。

调用dfs函数开始生成全排列。这个函数接收一个参数d,表示当前正在处理第d个位置的元素。在dfs函数中,我们首先检查是否已经处理完所有位置的元素(即d == n + 1)。如果是,那么我们就输出当前的排列,并返回。

如果还有位置没有处理,我们就遍历所有的数字,尝试将它们放在当前位置。对于每一个数字,我们首先检查它是否已经被使用过(即vis[i]是否为1)。如果没有被使用过,我们就标记它为已使用,将它放在当前位置,然后递归地处理下一个位置。递归返回后,我们需要取消对当前数字的使用标记,以便于它可以被放在其他位置。这就是典型的回溯思想。


AC代码

#include 
#include 
#define AUTHOR "HEX9CF"
using namespace std;

const int N = 10;

bitset<N> vis;
int a[N];

int n;

void dfs(int d) {
	if (d == n + 1) {
		for (int i = 1; i <= n; i++) {
			cout << a[i] << " \n"[i == n];
		}
		return;
	}
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			vis[i] = 1;
			a[d] = i;
			dfs(d + 1);
			vis[i] = 0;
		}
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

    vis.reset();
	cin >> n;
	dfs(1);
	return 0;
}

你可能感兴趣的:(Algorithm,Problems,深度优先,算法,图论)