AcWing 843. n-皇后问题 (dfs)

本文详细介绍了经典的N皇后问题及其两种不同的深度优先搜索(DFS)解法。第一种解法通过原始的DFS搜索,对每个格子判断是否可以放置皇后;第二种解法优化了搜索过程,确保每行只放一个皇后。每种解法都提供了相应的C++代码实现,并在解题过程中进行了状态管理,确保皇后不会相互攻击。
摘要由CSDN通过智能技术生成

题目链接 : 点击查看

题目描述 :

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;
} 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在森林中麋了鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值