递归要实现排列型枚举大概需要用到两次for循环,第一次遍历数字(第一个for循环),确保每个可用的数字我们都能找到,就是在每个深度u上,当前可用的数字都会被尝试一遍,直到找到所有长度为n的排列。
第二次for循环,回溯,每个dfs递归结束后,清空数组state的值,以方便重新利用数字,中间的条件很重要if(!used[i]) 中的 ! 表示逻辑非运算符,用于取反操作,其作用是将 used[i] 的值取反,即如果 used[i] 为 false 则取反后为 true,如果 used[i] 为 true 则取反后为 false。
在这段代码中,used[i] 数组用于标记数 i 是否已经被使用过,因此 !used[i] 的意思是数 i 还没有被使用过,也就是说数 i 可以被填入当前位置 u。这个东西自我感觉应该算是点睛之笔。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=10;//常量定义
int n;//表示要求解n个数的全排列
int state[N];//存储每个排列的状态
bool used[N];//表示数字是否已被使用
void dfs(int u)//边界
{
if(u>n)//搜索结束,输出排列
{
for(int i=1;i<=n;i++) printf("%d ",state[i]);//输出排列 ,这种皇鞘涑龅谝淮闻帕?
puts("");//换行
return;
}
for(int i=1;i<=n;i++)//搜索下一个未被使用的数字 ,这个循环用于全排列,保证其它的排列组合都可以出现
if(!used[i])
{
state[u]=i;//将该数字加入当前排列中
used[i]=true;//标记该数字已被使用
dfs(u+1);//搜索下一个位置
state[u]=0;//回溯,将该数字从排列中删除
used[i]=false;//回溯,标记该数字未被使用
}
}
int main()
{
scanf("%d",&n);//输入要求解的全排列的数字个数
dfs(1);//从第一个位置开始搜索
return 0;//结束程序
}