N皇后问题

        所谓N皇后问题,就是在一个N*N棋盘上放置N个皇后,每一个皇后所在的行,列以及它的对角线都只能有其自身,我们需要统计N个皇后时满足皇后布置的情况。

题目图解如下:

在5*5的棋盘上放置5个皇后,每个皇后所在的行,列以及它所对应的对角线都只有其自身,以下是满足皇后摆放位置的一种情况:

 

可以看到,每个皇后的位置都符合题目的规定,给个皇后所在的行,列以及其对角线都只有它自己

我们需要找出满足这种皇后摆放的所有解法。

但是下面的皇后的拜访就出了问题,因为第二行第五列的皇后的对角线上有其他的皇后 

在一个棋盘中,我们一般将其看成二维数组,这样能够很直观的看到皇后的位置,但其实我们也可以通过一维数组来表示此二维数组

一维数组a[i],i相当于行数,a[i]的值相当于列

全局变量n定义了皇后的个数以及行数,列数

全局变量cnt统计皇后有多少种摆法

#define N 100
int a[N];//i代表行,a[i]代表列,用一维数组就足够了
int cnt;//皇后的摆法
int n;//皇后摆放的行数,皇后的数量和行数一致

我们在摆放皇后时,可以定义一个函数来表示,函数的形参为摆放皇后开始摆放在哪一行的行数

当我们摆放到最后一行(也就是棋盘的边界)时,证明当前的N皇后情况摆放完毕,那么统计皇后的摆放的计时器cnt++

row==n+1为边界,因为我们从一维数组下标为1开始摆放,不考虑一维数组下标为0的行。

void dfs(int row) {//表示第row皇后放在何处
	if (row == n + 1) {
		//都到达边界了,那就产生了一组解
		cnt++;
		return;//返回
	}
}

如果此时还不是边界,也就是1-n行的位置,那么我们每一次摆放皇后的时候,

都需要判断当前(行,列)位置能否放置符合题目要求的皇后:

//从第一列遍历到最后一列
	for (int i = 1; i <= n; i++) {
		//调用check函数查看这一行这一列能不能放皇后
		if (check(row, i)) {
			a[row] = i;// 放置皇后     因为a[row]的结果充当了列数
			dfs(row + 1);//放下一位置的皇后   直到row==n+1产生一组解
			a[row] = 0;//移除当前位置的皇后   回溯的关键步骤,允许算法尝试在同一行的其他列放置皇后
		}
	}

a[row]=0这步不能省略,不然就无法得到正确的答案。 

对于check函数:我们需要确定摆放皇后的行,列以及对角线的规律 

因为我们是从行来摆放的,如果行数当前的列数不能摆放皇后,已经通过a[row]来移除皇后,在后面的列数重新寻找符合摆放皇后的列,因此在check函数中,我们不需要考虑判断行的摆放。

check(int x,int y){//传入摆放皇后的行数,列数

}

皇后它所在的列只能有它自己,因此:a[i]==y时,摆放的位置不符合,返回false 

皇后它所在的对角线只能有它自己,而对角线有两种情况:

对于一、三象限的对角线:它们的横坐标与纵坐标相加都是相同的值,因此:i+a[i]==x+y时,摆放的位置不符合,返回false

对于二、四象限的对角线:它们的横坐标与纵坐标的差都是相同的值,因此:i-a[i]==x-y时,摆放的位置不符合,返回false

除了以上位置,其余位置都可以放置皇后,此时返回true

bool check(int x, int y) {//传进去行和列
	for (int i = 1; i <= x; i++) {
		if (a[i] == y) return false;
		//两条对角线,一条和相等,一条差相等
		if (i + a[i] == x + y) return false;
		if (i - a[i] == x - y) return false;
	}
	return true;
}

以下是完整的代码:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//n皇后问题
//皇后在同一行,同一列,以及对角线上只能有一个
#define N 100
int a[N];//i代表行,a[i]代表列,用一维数组就足够了
int cnt;//皇后的摆法
int n;//皇后摆放的行数,皇后的数量和行数一致
//check函数用来判断当前位置能不能放置皇后
bool check(int x, int y) {//传进去行和列
	for (int i = 1; i <= x; i++) {
		if (a[i] == y) return false;
		//两条对角线,一条和相等,一条差相等
		if (i + a[i] == x + y) return false;
		if (i - a[i] == x - y) return false;
	}
	return true;
}
void dfs(int row) {//表示第row皇后放在何处
	if (row == n + 1) {
		//都到达边界了,那就产生了一组解
		cnt++;
		return;
	}
	//从第一列遍历到最后一列
	for (int i = 1; i <= n; i++) {
		//调用check函数查看这一行这一列能不能放皇后
		if (check(row, i)) {
			a[row] = i;// 放置皇后     因为a[row]的结果充当了列数
			dfs(row + 1);//放下一位置的皇后   直到row==n+1产生一组解
			a[row] = 0;//移除当前位置的皇后   回溯的关键步骤,允许算法尝试在同一行的其他列放置皇后
		}
	}

}
int main() {
	scanf("%d", &n);//输入几个皇后
	dfs(1);//从第一行放起
	printf("%d", cnt);
}

这个代码能够解决N皇后的问题,但是使用的时间却不是最优解,可以说是暴力解法,如有错误还请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值