今天我们接着来学习dfs(枚举)
1.枚举排列
在之前的搜索枚举中,我们并没有考虑选入物品的 排列顺序。但在一些题目中,会要求考虑给定数字或物品的排列,这种排列可以是在
n 个中的所有符合要求的全排列,也可以是在
n 中找到长度为 k 的排列。
如果使用我们之前的搜索枚举方法,我们发现难以用参数标记原数组中数字的选取情况,那么我们就需要一个全局的布尔数组,帮助我们标记哪些数字已经被选入了排列。另一方面,由于我们使用了这样的全局标记数组,那么必然在搜索时使用到 回溯 技巧,在这个分支的搜索结束后,将标记数组还原。
若要输出 n 个数字全排列,在 dfs 数组中需要的参数需要包含已经选入的数字,在选取当前位数字后进行搜索后,要注意进行回溯
cpp
int n;
int per[N];
bool vis[N];
void dfs (int dep) {
if (dep == n) {
for (int i = 0; i < n; i++) {
cout << per[i] << " ";
}
cout << endl;
return;
}
for (int i = 1; i <= n; i++) {
if(vis[i]) {
continue;
}
vis[i] = true;
per[dep] = i;
dfs(dep + 1);
vis[i] = false;
}
如果想要输出 n 个数字的 k 排列,我们可以在之前代码上进行一些较小的修改。当我们选取到 k 个数字时就应该停止继续搜索枚举的过程。
cpp
int n;
int per[N];
bool vis[N];
void dfs (int dep) {
if (dep == k) {
for (int i = 0; i < k; i++) {
cout << per[i] << " ";
}
cout << endl;
return;
}
for (int i = 1; i <= n; i++) {
if(vis[i]) {
continue;
}
vis[i] = true;
per[dep] = i;
dfs(dep + 1);
vis[i] = false;
}
}