这篇题解主要对比两种解法中我自己的一点思考
解法一 我一开始疑问为什么解法一没有定义状态s 而解法二中需要定义 s 其实核心还是没有理解透彻代码
因为解法一自带剪枝操作 如果没有满足N皇后排列条件 u不会++到满足条件 而解法二无论是否满足条件都会搜索下去
所以解法需要用状态s来定义,那么是否可以优化呢? 是否可以把搜索弄到里面去? emmm暂时留个疑问看看吧讲道理
#include <iostream>
using namespace std;
const int N = 20;
// bool数组用来判断搜索的下一个位置是否可行
// col列,dg对角线,udg反对角线
// g[N][N]用来存路径
int n;
char g[N][N];
bool col[N], dg[N], udg[N];
void dfs(int u)
{
// u == n 表示已经搜了n行,故输出这条路径
if (u == n)
{
for (int i = 0; i < n; i ++ ) puts(g[i]); // 等价于cout << g[i] << endl;
puts(""); // 换行
return;
}
//对n个位置按行搜索
for (int i = 0; i < n; i ++ )
// 剪枝(对于不满足要求的点,不再继续往下搜索) udg[n - u + i],+n是为了保证大于0
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;
}
解法二:解法二中dfs传入三个参数, x,y,s x,y是坐标 自然容易理解 s 其实也容易理解,因为dfs中对是否打印输出有一个判断 需要s==n 递归 和递归后的清零都是常规操作
对角线和反对角线 其他的点看以后再来慢慢补充吧
// 不同搜索顺序 时间复杂度不同 所以搜索顺序很重要!
#include <iostream>
using namespace std;
const int N = 20;
// 因为是一个个搜索,所以加了row
int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N];
// s表示已经放上去的皇后个数
void dfs(int x, int y, int s)
{
// 处理超出边界的情况
if (y == n) y = 0, x ++ ;
// 说明已经放好了n个皇后,表示枚举完 n^2 个了
if (x == 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;
}