AcWing原题链接:n-皇后问题
算法思路
根据之前写过的数的排列的深度优先搜索dfs的思想,将path[]
看作是每一行放置皇后的位置,每次在一行中找到一个合法的皇后的位置,便进行下一次递归:dfs(u + 1)
,这就是找到了一个皇后的位置。
而判断该位置是否合法的条件是:在当前递归所处的行数中,遍历每一列的棋格,正在遍历的这一格的数列、对角线、反对角线都没有皇后。
用col[N]
表示这一列有无queen
dg[N]
表示这一格的对角线上有无queen
udg[N]
表示这一格的反对角线上有无queen
合法条件因此为:!col[i] && !dg[u + i] && !udg[u - i + n]
因为是根据竖列进行递归的,所以每一横行都只有一个queen,就不用判断这一排有无queen了
对角线和反对角线的理解有两种:
1. 好理解一点的就是越往右下,i
和u
都增大
越往左下,i
减小,u
增大,+n
是为了防止下标出现负数
2. 另一种理解方式是通过直角坐标系的截距进行理解:
row = -col + b => b = u + 1
row = col - n + b => b = u + n - i
算法实现
#include <iostream>
using namespace std;
const int N = 20;
int n; // 棋盘的排列总数
char g[N][N]; // 存储棋盘信息,·为无,Q为queen
bool col[N], dg[N * 2], udg[N * 2]; // col[N] 这一列是否有queen
// dg[N] 对角线上有无queen
// udg[N] 反对角线上有无queen
void dfs(int u) {
/*
注意这里的答案格式控制,我错了两边
第一次错是因为没仔细审题,棋盘每格子之间不用空格
第二次错是因为每个答案之间有回车进行分隔
*/
if (u == n) {
for (int i = 0; i < n; i ++)
cout << g[i] << endl;
cout << endl;
return ;
}
/*
row = u
col = i
dg = u + i
udg = u - i + n
对角线和反对角线的理解有两种:(见图解)
1. 好理解一点的就是越往右下,i和u都增大
越往左下,i减小,u增大,+n是为了防止下标出现负数
2. 另一种理解方式是通过直角坐标系的截距进行理解:
row = -col + b => b = u + 1
row = col - n + b => b = u + n - i
*/
for (int i = 0; i < n; i ++) { // 竖列进行遍历
if (!col[i] && !dg[u + i] && !udg[u - i + n]) {
g[u][i] = 'Q';
col[i] = dg[u + i] = udg[u - i + n] = true;
dfs(u + 1); // 每递归一层就是一横排,递归到u == n 为止
col[i] = dg[u + i] = udg[u - i + n] = 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;
}
总结
注意答案格式控制,我错了两遍
第一次错是因为没仔细审题,棋盘每格子之间不用空格
第二次错是因为每个答案之间有回车进行分隔