dfs深度优先搜索分析方法
dfs最重要的使搜索顺序。即使用什么顺序搜索遍历所有方案。以例题842. 排列数字
按照图中所示的顺序对所有方案进行遍历。
算法:
- 用 path 数组保存排列,当排列的长度为 n 时,是一种方案,输出。
- 用 st 数组表示数字是否用过。当 state[i] 为 1 时:i 已经被用过,st[i] 为 0 时,i 没有被用过。
- dfs(i) 表示的含义是:在 path[i] 处填写数字,然后递归的在下一个位置填写数字。
- 回溯:第 i 个位置填写某个数字的所有情况都遍历后, 第 i 个位置填写下一个数字。
#include <iostream>
using namespace std;
const int N = 10;
int path[N];
int n;
bool st[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])
{
path[u] = i;
st[i] = true;
dfs(u + 1);
// 恢复现场
path[u] = 0;
st[i] = false;
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
例843 n皇后问题
第一种搜索顺序(全排列的搜索顺序)
#include <iostream>
using namespace std;
const int N = 10;
int n;
char g[N][N];
bool col[N], dg[N], udg[N];
void dfs(int u)
{
if (u == n)
{
for (int i = 0; i < n; ++i) puts(g[i]);
puts("");
return;
}
for (int i = 0; i < n; ++i)
{
if (!col[i] && !dg[u + i] && !udg[n - u + i])
{
g[u][i] = 'Q';
// 列,对角线,反对角线
col[i] = dg[u + i] = udg[n - u + i] = true;
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] = '.';
dfs(0);
return 0;
}
第二种摆法
注意对角线的处理,s表示放置n皇后的数目。记住需要恢复现场
步骤:
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool col[N], dg[N], udg[N], row[N];
void dfs(int x, int y, int s)
{
// s 表示摆放的皇后个数
if (y == n) y = 0, ++x;
if (x == n)
{
// 如果放置皇后数量 == n
if (s == n)
{
for (int i = 0; i < n; ++i) puts(g[i]);
puts("");
}
return;
}
// 不放皇后
dfs(x, y + 1, s);
// 放皇后
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
{
g[x][y] = 'Q';
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
dfs(x, y + 1, s + 1);
row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
g[x][y] = '.';
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
g[i][j] = '.';
dfs(0, 0, 0);
return 0;
}