题目链接 : 点击查看
题目描述 :
n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。如图
现在给定整数 n (1≤n≤9),请你输出所有的满足条件的棋子摆法。
输入输出格式 :
输入
共一行,包含整数 n。
输出
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中
.
表示某一个位置的方格状态为空,Q
表示某一个位置的方格上摆着皇后。每个方案输出完成后,输出一个空行。
输入输出样例 :
输入
4
输出
. Q . .
. . . Q
Q . . .
. . Q .. . Q .
Q . . .
. . . Q
. Q . .
题目分析 :
本题是经典的dfs题目,根据搜索的顺序不同,分成两种解法。第一种是原始的搜索,对于棋盘上的每一个格子,都有两种状态,放皇后和不放皇后,我们对于每一个格子都进行判断和向下搜索。第二种解法是优化版的搜索,我们从题目总结出,每一行只能放一个皇后,我们在一行放完皇后之后,直接进入下一行进行搜索。
我们先具体来看第一种解法,我们定义在dfs里有三个参数x、y、s,x、y即表示棋盘的横纵坐标,s表示放置的放置的皇后的个数。对于当前位置,我们来确定放不放皇后,如果不放皇后,则向下一个格子进行搜索即dfs(x, y + 1 , s)(特别的,在主函数中我们将每个格子都初始化为' . ' ), 如果放皇后我们要先对当前格子进行判断,看是否与另一个皇后在同一行、或同一列或同一对角线或反对角线,如果出现上述一种情况,则不能放置,判断条件的代码为:if (!row[x] && !col[y] && !dg[x+ y] &&!udg[n + x - y) (x + y是当前坐标在哪条对角线上,n + x - y是当前坐标在哪条反对角线上,在此不给出具体的推理过程)。如判断能成功放置,则将 row[x] = col[y] = dg[x + y] = udg[x - y + n] = true 即将将要放置的皇后所在行、所在列、所在对角线反对角线都进行标记,表明不可用。将点g[x][y]改为Q,再dfs(x, y + 1, s + 1)继续向下搜索,搜索之后要进行状态恢复,即row[x] = col[y] = dg[x + y] = udg[x - y + n] = false、g[x][y] = '.'。要注意的是,当y == n时要进入下一行且y要从头开始。递归的出口条件是x == n 但是当s == n时(皇后全部放完时)才将棋盘进行输出。以上就是第一种解法的解题过程。详见如下代码。
代码 :
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 10;
bool col[N], row[N], dg[N * 2], udg[N * 2];
char g[N][N];
int n;
void dfs(int x, int y, int s) {//s表示放置皇后的个数
if (s > n) return ;
if (y == n) y = 0, x ++ ;
if (x == n) {
if (s == n) {
for (int i = 0; i < n; i ++ ) puts(g[i]);
cout << endl;
}
return ;
}
dfs(x, y + 1, s);//当前位置不放置皇后
if (! row[x] && ! col[y] && ! dg[x + y] && ! udg[n + x - y]) {//当前位置要放置皇后
row[x] = col[y] = dg[x + y] = udg[n + x - y] = true;
g[x][y] = 'Q';
dfs(x, y + 1, s + 1);
g[x][y] = '.';
row[x] = col[y] = dg[x + y] = udg[n + x - y] = false;
}
}
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;
}
-------------------------------------------------------------------------------------------------------------------
然后我们再来看第二种解法,第二种解法是对第一种解法的提炼,与第一中解法不同的是定义dfs只有一个参数u,表明当前搜索到的行数,如果u == n则表明当前情况搜索完成,将数组g[N][N]进行输出。用for循环来遍历每一列的情况,如果当前列满足搜索条件即!col[i] && !dg[u + i] && !udg[n + u - i],则在当前位置放置皇后,然后跳到下一行进行搜索即dfs(u + 1)。这样就保证了每一行就放置一个皇后,不用判断当前行是否有其他皇后。其他方面与解法一相同,详见如下代码。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 20;
int n;
char g[N][N];
bool col[N], dg[N], udg[N];
void dfs(int u) {
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;
}