算法学习笔记(21)——深度优先搜索DFS
深度优先搜索DFS
深度优先搜索的思想简单来说就是“一条道走到黑”,也被称为“暴力搜索”,常用于解决需要给出所有方案的问题,因为它的搜索顺序就是能够得到一个完整的搜索路径(方案)后回溯再去搜索其它的方案。
排列数字
#include <iostream>
using namespace std;
const int N = 10;
int n;
int path[N];
bool st[N];
void dfs(int u)
{
if (u == n) {
for (int i = 0; i < n; i ++ ) cout << path[i] << ' ';
puts("");
return;
}
for (int i = 1; i <= n; i ++ ) {
if (!st[i]) {
path[u] = i;
st[i] = true;
dfs(u + 1);
st[i] = false; // 恢复现场
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}
n-皇后问题
这道题限制了任意两个皇后都不能处于同一行、同一列或同一斜线上,所以我们开行row
、列col
、正对角线dg
、反对角线udg
这四个数组用于判断当前位置能否放皇后。有两种搜索方式:
按位搜索
#include <iostream>
using namespace std;
const int N = 10, M = N * 2;
int n;
char g[N][N]; // 用于存储地图
bool row[N], col[N], dg[M], udg[M];
// 深搜函数,(x,y)表示坐标,s代表当前放置的皇后个数
void dfs(int x, int y, int s)
{
// 已经放了n个皇后,则返回
if (s > n) return;
// 如果已经扫描到当前行的最后一个位置,则从下一行的开头开始
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;
}
g[x][y] = '.'; // 默认当前位置没有皇后,也可以在main中对地图初始化
// 要么放皇后
if (!row[x] && !col[y] && !dg[x + y] && !udg[n - x + y]) {
g[x][y] = 'Q';
row[x] = col[y] = dg[x + y] = udg[n - x + y] = true;
dfs(x, y + 1, s + 1); // 搜索下一个位置,皇后数加一
row[x] = col[y] = dg[x + y] = udg[n - x + y] = false; // 恢复现场
g[x][y] = '.';
}
// 要么不放皇后
dfs(x, y + 1, s);
}
int main()
{
cin >> n;
dfs(0, 0, 0);
return 0;
}
按行搜索
由于每一行最多只能放一个皇后,所以我们可以按行来搜索,每次枚举一行时就放一个皇后,放到第n行时一定有n个皇后。
#include <iostream>
using namespace std;
const int N = 10, M = N * 2;
int n;
char g[N][N];
bool col[N], dg[M], udg[M];
void dfs(int u)
{
// 如果枚举到第n行,则一定放了n个皇后,输出结果
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;
}