AcWing 843. n-皇后问题
原题链接
中等
作者:
LingYunX
,
2021-02-15 12:13:15
,
所有人可见
,
阅读 300
y总在课里面讲了当对角线是 y = x + b的形式时候
b = y - x, 为了让b恒大于0,所以N要开2倍,并且b = y - x + n
y应该表示行数,x应该表示列数,但是y总在写的时候写成了 ndg[n - u + i]
这里的i应该表示列数,讲的和写的有点偏差,但是不影响结果
在我的代码中,row表示行数,i同样代表列数,ndg[row - i + n]; 结果是没有错的。
算法1
(暴力枚举) 全排列方式
C++ 代码
//全排列求解
#include <iostream>
using namespace std;
const int N = 20;
// dg表示左上到右下的对角线
// ndg表示左下到右上的对角线
bool col[N], dg[N], ndg[N];
char g[N][N];
int n;
void dfs(int row){
if (row == n){
for (int i = 0; i < n; i ++ ) puts(g[i]);
puts("");
return ;
}
// 在row确定的前提下,按列来筛选
for (int i = 0; i < n; i ++ ){
if (!col[i] && !dg[row + i] && !ndg[row - i + n]){
// ndg: y = x + b -- > b = y - x + n(保证b大于0)
// y总的课中表示方式可能和我的有点区别,y总讲的是y - x + n 应该写成 row - i + n
// 但是y总写成了n - row + i,当然这不影响结果。
col[i] = dg[row + i] = ndg[row - i + n] = true;
g[row][i] = 'Q';
dfs(row + 1);
col[i] = dg[row + i] = ndg[row - i + n] = false;
g[row][i] = '.';
}
}
}
int main(){
cin >> n;
for (int i = 0; i < n; i++ ){
for (int j = 0; j < n; j ++ ){
g[i][j] = '.';
}
}
// 一行一行的使用dfs,这样就直接保证了不在同一行,因此可以不用判断行
dfs(0);
return 0;
}
算法2
不指定行,以x和y的坐标为导向
时间复杂度 O(n * n!)
C++ 代码
//求解法 时间复杂度较高,比较慢
#include <iostream>
using namespace std;
const int N = 20;
bool row[N], col[N], dg[N], ndg[N];
char q[N][N];
int n;
//开始判断的坐标 (x, y) 当前皇后数目s
void dfs(int x, int y, int s){
if (y == n){
x ++;
y = 0;
}
if (x == n){
if (s == n){
for (int i = 0; i < n; i++ ) puts(q[i]);
puts("");
}
return;
}
// 不放皇后
dfs(x, y + 1, s);
if (!row[x] && !col[y] && !dg[x + y] && !ndg[n - y + x]){
q[x][y] = 'Q';
row[x] = col[y] = dg[x + y] = ndg[n - y + x] = true;
dfs(x, y + 1, s + 1);
row[x] = col[y] = dg[x + y] = ndg[n - y + x] = false;
q[x][y] = '.';
}
}
int main(){
cin >> n;
for (int i = 0; i < n ; i ++ )
for (int j = 0; j < n;j ++ )
q[i][j] = '.';
dfs(0, 0, 0);
return 0;
}