一、问题描述
在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;
}