八皇后问题——程序设计艺术与方法实验二 搜索算法的实现

八皇后问题——程序设计艺术与方法实验二 搜索算法的实现

八皇后问题: 在一个国际象棋棋盘上放八个皇后,使得任何两个皇后之间不相互攻击,求出所有的布棋方法。上机运行并检验结果。

分析:
国际象棋中关于皇后的可吃子范围的规则:
与皇后处在同一行中,同一列中,两个对角线方向的所有位子(格子)。
在这里插入图片描述

思路:
① 由规则可知,在棋盘的每行、每列及每条对角线上只能放置一个棋子方能满足上述条件。
② 因此,依次在每行(列)中试探着找一个合适的位置来放置棋子(此处不妨逐列试探),在能和已放置的棋子相容的前提下,继续其他列上位子的搜索。
③ 若本列没有合适的位置,则说明其前面的放置方法不合适,因而需要重新放置,即需要将原来所放的棋子去掉,再重新往下试探。
④ 去掉的次序按照最后试探的棋子最先去掉的原则进行(类似于图的深度遍历算法中的回溯)。

本题算法可用递归方式来描述。算法所需的参数如下:
(1)当前正在试探的列号(不妨用j表示);
(2)已经存放的各棋子;
(3)考虑到通用性, 将棋盘的行列数n作为一参数。
在实现时,需要注意以下问题的解决:
(1)如何表示棋盘中放置的棋子;
(2)某位置能放置一个棋子的条件的判断;
(3)前面的放置不行时,如何重新放置;
由于每行、列及对角线上只能有一个棋子,因而对每列来说,只需记录该列中的棋子所在的行号,因而用一维数组即可。如下面棋盘中的所放棋子及表示如下:

在这里插入图片描述
代码:

#include<iostream>
using namespace std;
/*八皇后问题:设计算法在国际象棋棋盘上放置八个皇后, 以使其中任意两个不能互相吃掉对方。
解:首先应了解一下国际象棋中关于皇后的可吃子范围的规则:与皇后处在同一行中,同一列中,两个对角线方向的所有位子(格子)。
问题分析:
由规则可知,在棋盘的每行、每列及每条对角线上只能放置一个棋子方能满足上述条件。
因此,本题可这样考虑:依次在每行(列)中试探着找一个合适的位置来放置棋子(此处不妨逐列试探),在能和已放置的棋子相容的前提下,继续其他列上位子的搜索。
若本列没有合适的位置,则说明其前面的放置方法不合适,因而需要重新放置,即需要将原来所放的棋子去掉,再重新往下试探。
去掉的次序按照最后试探的棋子最先去掉的原则进行(类似于图的深度遍历算法中的回溯)。
重复这一操作过程,直到所放棋子满足条件为止。
*/
int x = 1;
//(2)某位置能放置一个棋子的条件的判断
bool OK(int* a, int i1, int j1, int n) {//判断第j列的第i行能否放置
	//初始化
	int i = i1, j = j1; bool ok = true;
	//检验前面j-1列是否选了第i行
	while (j > 1 && ok) {
		j--; ok = a[j] != i;
	}
	//重新回溯,检验主对角线上是否有元素
	i = i1; j = j1;
	while (j > 1 && i > 1 && ok) {
		j--; i--; ok = a[j] != i;
	}

	//重新回溯,检验副对角线上是否有元素
	i = i1; j = j1;
	while (j > 1 && i < n && ok) {
		j--; i++; ok = a[j] != i;
	}

	return ok;
}

void Print(int* a, int n) {
	cout <<"第"<< x++ <<"种方法———"<< " 棋盘中每列中的棋子所在的行号:(";
	for (int i = 1; i < n; i++)
		cout << a[i] << " ";
	cout << a[n] << ")";
	cout << endl;
}
//按列开始遍历
void Queen(int* a, int j, int n) {
	if (j > n)
		Print(a, n);
	else
		for (int i = 1; i <= n; i++) {
			if (OK(a, i, j, n)) {
				a[j] = i;
				Queen(a, j + 1, n);
			}
		}
}

int main() {
	cout << "请输入棋盘规格(n行n列的n):";
	int n;
	cin >> n;
	int* a = new int[n + 1];
	cout << "皇后的位置有:" << endl;
	Queen(a, 1, n);
	return 0;
}

//思考:n也可以作为全局变量

运行结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值