食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目侧重题目分析,代码实现,以及必要的代码理解误区
题目描述:
-
n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n。输出格式
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q…
…Q
Q…
…Q.…Q.
Q…
…Q
.Q… -
题目来源:https://www.acwing.com/problem/content/845/
题目分析:
- dfs经典题目,n皇后问题
- 注意,给定棋盘行数n后,可能有多种合理结果
算法原理:
模板算法:
- 传送门:DFS
n皇后问题:
-
难点:
行数可以使用row[]数组记录
列数可以使用col[]数组记录
一三象限角平分线使用row[y + x]表示
二四象限角平分线使用row[y - x + n]表示 -
放置棋子有三种放置方法:
- 按行放置,每行放置一个
- 按列放置,每列放置一个
- 按个放置,每个放置0 / 1个
下面来讲解按列放置 & 按个放置
按列放置:
- 共n列,递归n层,每层遍历一列的n个格
- 对放置点的要求:
不共行,不共列,不共一三角分线,不共二四角分线 - 还原:
当该列选择一个放置完成后,清除放置。
再从同列其余格子中选择可放置点进行放置 - 代码:
#include <iostream>
using namespace std;
const int N = 9 + 1;
int n;
char arr[N][N];
void init(){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
arr[i][j] = '.';
}
}
}
void print(){
for(int i=1; i<=n; i++){
for(int j = 1; j<=n; j++){
cout <<arr[i][j];
}
cout<<endl;
}
}
int row[N], col[N], dg[N],udg[N];
void dfs(int x){
if (x == n+1) {print(); cout<<endl; return;}
for(int i=1; i<=n; i++){
if (!row[i] && !dg[x+i] && !udg[n+x-i]){
arr[i][x] = 'Q';
row[i] = 1, dg[x+i] = 1, udg[n+x-i] = 1;
dfs(x+1);
arr[i][x] = '.';
row[i] = 0, dg[x+i] = 0, udg[n+x-i] = 0;
}
}
}
int main(){
cin >>n;
init();
dfs(1);
return 0;
}
按个放置:
- 共n个棋子,递归n层,每层遍历n*n格
- 对放置点的要求:同上
- 还原:
还原列标记 行标记 斜线标记
还原后看下一格 - 代码:
#include <iostream>
using namespace std;
const int N = 9+1;
int n;
char g[N][N];
bool row[N], col[N], dg[N], udg[N];
void init(){
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
g[i][j] = '.';
}
}
}
void print(){
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
cout<<g[i][j];
}
cout<<endl;
}
}
void dfs(int x, int y, int cnt)
{
if (y == n) y = 0, x++ ;
if (x == n) {
if (cnt == n) {
print();
cout<<endl;
}
return;
}
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] = 1;
dfs(x, y + 1, cnt + 1);
row[x] = col[y] = dg[x + y] = udg[x - y + n] = 0;
g[x][y] = '.';
}
dfs(x, y + 1, cnt);
}
int main() {
cin >> n;
init();
dfs(0, 0, 0);
return 0;
}
代码误区:
1. 为什么一三角分线为x+y,二四角分线为x-y+n?
- 很多时候就是试试看,尤其考试时,试试看发现正确了就记住结论
- 先假设一个是x+y,一个是x-y
防止越界,x-y后+n - 画图到二维数组中去验证
本篇感想:
-
dfs部分不难,难在所谓的正反斜线的记录
-
本篇很接近我们讲完模板之后的刷题博客了
-
40篇达成,照例上美图:
-
看完本篇博客,恭喜已登 《筑基境-初期》
距离登仙境不远了,加油