DFS俩个核心
- 回溯
- 剪枝:提前可以判断该方案不合法,所以没有必要继续往下搜了,直接把下面减掉直接回溯。
题目
俩种方法:
- 第一种方法:按枚举的,每一行只有一个皇后,枚举的时候,就保证每一行只有一个,所以没有row[N]。对行进行深度遍历。
- 第二种方法:每个位置都有俩种情况,要么放皇后,要么不放皇后
方法1:
- 对于第 r 行的第 i 个位置,判断每个点是否可以放皇后,如果可以,则放皇后,然后处理 r + 1 行。直到 r = n,程序指行完毕。
#include <iostream>
using namespace std;
const int N = 20; //正反对角线,所以是20
// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线,点对应的两个斜线以及列上是否有皇后
// g[N][N]用来存路径,存储棋盘
int n;
char g[N][N];
bool col[N], dg[N], udg[N]; //表示状态位,没被占用为false,否则为true
void dfs(int u )
{
if (u == n) //放满了棋盘,输出棋盘,已经搜了n行,故输出这条路径
{
for (int i = 0; i < n; i ++) puts(g[i]);
puts(""); //换行
return;
}
for (int i = 0; i < n; i ++) //第 u 行,第 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] = '.';
}
}
return;
}
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;
}
也可以这样写
if (u == n) //放满了棋盘,输出棋盘,已经搜了n行,故输出这条路径
{
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < n; j ++)
cout << (g[i][j]);
puts(""); //换行
}
cout << endl;
return;
}
时间复杂度为O(n!)
对角线dg[u + i]
,反对角线udg[n - u + i]
中的下标u+i
+i和n−u+i
表示的是截距
- 下面分析中的(x,y)相当于上面的(u,i)
反对角线
y=x+b
截距b=y−x
,因为我们要把 b 当做数组下标来用,显然 b 不能是负的,所以我们加上+n
(实际上+n+4
,+2n
都行),来保证是结果是正的,即y - x + n
- 而对角线
y=−x+b
截距是b=y+x
=,这里截距一定是正的,所以不需要加偏移量
方法2:
- 从第一行的第一列,开始依次放皇后
// 不同搜索顺序 时间复杂度不同 所以搜索顺序很重要!
#include <iostream>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N]; // 因为是一个个搜索,所以加了row
// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
// 处理超出边界的情况
if (y == n) y = 0, x ++ ;
if (x == n) { // x==n说明已经枚举完n^2个位置了
if (s == n) { // s==n说明成功放上去了n个皇后
for (int i = 0; i < n; i ++ ) puts(g[i]);
puts("");
}
return;
}
// 分支1:放皇后
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] = '.';
}
// 分支2:不放皇后
dfs(x, y + 1, s);
}
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;
}