在八皇后问题中,每个皇后所在行,列,左右对角线都是不能有其他皇后的,我们需要对每个点进行搜索,来看是否能满足要求,如果一个点被放置之后,后续出现了皇后之间可以互相攻击的问题,我们就需要回溯到上一层,尝试搜索这一层的其他列,循环往复,知道正确放置所有的皇后,那么我们怎么使用搜索与回溯进行解决呢,搜索与回溯有几大步

1.枚举所有方案

我们固定行,搜索这一行的每一列,

2.判断标记,看是否这一行一列能否放置皇后

3.标记,放置皇后

将这个皇后放置并且,标记他的攻击范围

4.搜索下一行

5.回溯

如果出现皇后之间可以互相攻击,我们就回溯

6.终止条件

当我们搜索到n+ 1 行的时候就说明前n个皇后已经正确放置在n行了,这时候我们打印输出棋盘即可

那么我们如何创建标记数组,并且做到只用行列的关系做到一维标记数组呢,

我们看列标记数组,如果这一列被标记那么所有的行就被标记了,

再看左斜,我们发现左斜对角上的点 i + j 都是相等的,标记了i j就相当于标记了这一对角线

同样的,右斜,我们发现i - j 都是同一个值,标记了 i  j就相当于标记了右对角线,但是我们发现,例如在4 皇后问题中,如果1,3点相减是会出现负数的问题,导致越界,所以我们需要加一个n(皇后数量) 来使其变正。

接下里就是代码样例,如果觉得有用麻烦点一个关注

#include <bits\stdc++.h>
using namespace std;

const int N = 8;
int n = 8;//八皇后
int a[N + 1][N + 1];//皇后的位置
bool vis_c[2 * N + 1];//列
bool vis_l[2 * N + 1];//左斜
bool vis_r[2 * N + 1];//右斜

int id = 1;

void dfs(int i) {
	//终止条件
	if (i == n + 1) {//前n个皇后已经正确放置了
		printf("NO. %d\n", id++);
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n;k++) {
				printf("%d ", a[j][k]);
			}printf("\n");
		}
	}

	//枚举第i行所有列的方案
	for (int j = 1; j <= n;j++) {
		if (!vis_c[j] && !vis_l[i + j] && !vis_r[i - j + n]) {//说明i ,j点的攻击范围里面没有皇后,可以搜
			//标记,放置皇后,标记攻击范围
			a[i][j] = vis_c[j] = vis_l[i + j] = vis_r[i - j + n] = 1;
			//搜索下一行
			dfs(i + 1);
			//回溯
			a[i][j] = vis_c[j] = vis_l[i + j] = vis_r[i - j + n] = 0;
		}
	}

}


int main() {


	dfs(1);

	return 0;
}

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐