DFS
每个DFS对应一个搜索树
(一条路走到黑)
例1:全排列
输入n,输出1~n数字的全排列。
使用DFS解决,填空 => 遍历每个空位 => 直至每个空位被填满
#include <iostream>
using namespace std;
const int N = 10;
int path[N]; //记录一组排序
bool st[N]; //记录i是否被用过
int n;
void dfs(int u)
{
//u==n 说明n个空已填满,此时u指向第n+1个空,此时需要输出这一组排序
if(u == n)
{
for(int i = 0; i < n; i++) printf("%d ",path[i]);
puts("");
return;
}
//遍历每个数字
for(int i = 1; i <= n; i++)
{
//若该数字未被使用,即可填入
if(!st[i])
{
path[u] = i;
st[i] = true;
dfs(u+1); //继续填下一个位置(直至每个位置都填上数字即u==n,下一步恢复状态,继续遍历未使用过的数字,若数字都被使用,继续回溯,恢复状态...)
st[i] = false; //恢复状态
}
}
}
int main()
{
cin >> n;
//从第0个空开始填
dfs(0);
return 0;
}
例2:n-皇后问题
解法1
采用的顺序为枚举每行每列。
g[N][N]
:用于存路径
col[N]
:所在列是否有皇后
dg[N]
:所在对角线是否有皇后
udg[N]
:所在反对角线是否有皇后
对于两个对角线的判断:可以用b代表不同的对角线。(在对角线中,为防止y-x
为负数,将其加上n
)
#include <iostream>
using namespace std;
const int N = 10;
char g[N][N];
int n;
bool col[N],dg[N],udg[N];
void dfs(int u)
{
if(u == n)
{
for(int i = 0; i < n; i++)
cout << g[i] << endl;
cout << endl;
return;
}
//遍历每一列
for(int i = 0; i < n; i++)
{
//剪枝(对于不满足要求的点,不再继续往下搜索)
if(!col[i] && !dg[u+i] && !udg[n-u+i])
{
col[i] = dg[u+i] = udg[n-u+i] = true;
g[u][i] = 'Q';
dfs(u+1);
col[i] = dg[u+i] = udg[n-u+i] = false;
g[u][i] = '.';
}
}
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
g[i][j] = '.';
//从第0行开始遍历
dfs(0);
return 0;
}
解法2
采用的顺序为枚举每一个格子
每一种格子有两种情况:放皇后与不放皇后,从左上角开始遍历。
#include <iostream>
using namespace std;
const int N = 10;
char g[N][N];
int n;
bool row[N],col[N],dg[N],udg[N];
void dfs(int x, int y, int s)
{
//列出界,跳到下一行第一个
if(y == n)
{
y = 0;
x++;
}
//遍历到第n行
if(x == n)
{
if(s == n) //n个皇后都放置完毕
{
for(int i = 0; i < n; i++)
cout << g[i] << endl;
cout << endl;
}
return;
}
g[x][y] = '.';
//分支1:放皇后
if(!row[x] && !col[y] && !dg[x + y] && !udg[y - x + n])
{
row[x] = col[y] = dg[x+y] = udg[y-x+n] = true;
g[x][y] = 'Q';
dfs(x,y+1,s+1);
row[x] = col[y] = dg[x+y] = udg[y-x+n] = false;
g[x][y] = '.';
}
//分支2:不放皇后
dfs(x, y+1, s);
}
int main()
{
cin >> n;
//从左上角开始遍历
dfs(0, 0, 0);
return 0;
}