【算法设计与分析】n后问题——设计一个解n后问题的队列式分支限界法,计算在n*n个方格上放置彼此不受攻击的n个皇后的一个放置方案。

文章介绍了如何使用分支限界法解决n皇后问题,即在n×n的棋盘上放置n个皇后,确保任意两个皇后不处于同一行、列或对角线上。程序读取input.txt文件中的棋盘大小n,并将解输出到output.txt。通过创建Node和Queen类,以及Place函数判断放置位置是否合法,实现了搜索解空间树的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

  在n* n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n皇后问题等价于在n*n格的棋盘上放置n个皇后,任何两个皇后不放在同一行或同一列或同一斜线上。
数据输入: 由文件input.txt给出输入数据。第1行有1个正整数n。
结果输出: 将计算的彼此不受攻击的n个皇后的一个放置方案输出到文件output.txt。文件的第1行是n个皇后的放置方案。

二、分析

  对于每一个放置点而言,它需要考虑四个方向上是否已经存在皇后。对于行,每一行只放一个皇后,直到我们把最后一个皇后放到最后一行的合适位置。对于列,列相同的约束条件,只需判断j是否相等即可。当前棋子和已放置好的棋子不能存在行数差的绝对值等于列数差的绝对值的情况,若存在则说明两个棋子在同一条斜线上。
  用分支限界法来解决n皇后问题。这里由于每一个合适的放置点出现最优解的概率是相等的,因此不需要使用优先队列,编译器提供了一个已经封装好的队列Queue。当输入n=8时,得到的一个结果如下。
在这里插入图片描述
  在input.txt文本中输入棋盘的格数为8。
在这里插入图片描述

三、运行结果

  运行程序,打开output.txt文本可以发现有如下解法。
在这里插入图片描述

四、代码

#include<iostream>
#include<queue>
#include<cmath>
#include<vector>
#include<fstream>
#include<sstream>
using namespace std;
//定义一个节点类
struct Node {
	int number;
	vector<int>x;//保存当前解 
};

//定义一个Queen的类 
class Queen {
	friend int nQueen(int);
public:
	bool Place(Node q, int n);
	void Research();
	int n;//皇后个数
	int* bestx;//最优解
};

//判断是否能够放置的函数 
bool Queen::Place(Node q, int n)
{
	for (int j = 1; j < n; j++)
		if ((abs(n - j) == abs(q.x[j] - q.x[n])) || (q.x[j] == q.x[n])) return false;
	return true;
}

void Queen::Research()
{
	queue<Node>Q;//活节点队列
	Node sign;
	sign.number = -1;
	Q.push(sign);//同层节点尾部标志
	int t = 1;//当前节点所处的层
	Node Ew;//当前扩展节点 
	Ew.number = 0;
	//搜索子集空间树
	while (1) {
		//检查所有的孩子节点 
		for (int k = 1; k <= n; k++) {
			//把当前扩展节点的值赋给下一个节点 
			Node q;
			q.number = t;
			q.x.push_back(0);//第一个位置为0 
			for (int i = 1; i < t; i++) q.x.push_back(Ew.x[i]);
			q.x.push_back(k);
			if (Place(q, t))
				Q.push(q);
		}
		//取下一扩展节点,取出,赋值给Ew 
		Ew = Q.front();
		Q.pop();
		if (Ew.number == -1) {
			//同层节点尾部标记
			t++;//进入下一层 
			Q.push(sign);//增加标记
			//继续往下去下一个节点 
			Ew = Q.front();
			Q.pop();
		}
		if (Ew.number == n) {//找到最后一层的节点 
			for (int i = 0; i <= n; i++) bestx[i] = Ew.x[i];
			break;
		}
	}
}

void nQueen(int n, ofstream& outfile)
{
	Queen X;
	X.n = n;
	X.bestx = new int[n + 1];
	for (int i = 0; i <= n; i++) X.bestx[i] = 0;
	X.Research();
	for (int i = 1; i <= n; i++) {
		outfile << X.bestx[i] << " ";
	}
}

int main() {
	int N;
	ifstream cinfile;
	cinfile.open("input.txt", ios::in);
	cinfile >> N;
	cinfile.close();
	ofstream outfile;
	outfile.open("output.txt", ios::out);
	nQueen(N, outfile);
	outfile.close();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会举重的薯片

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

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

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

打赏作者

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

抵扣说明:

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

余额充值