哈哈!经过三天的纠结debug之后,激动人心的、展示计算机作为伟大的智能机器的“N皇后问题”计算程序新鲜出炉啦!还带矩阵输出哦!是不是很像棋盘?
//问题描述:
//在N×N的棋盘上,放置N个皇后,使两两之间互不攻击。所谓互不攻击是指:
//(1)不在棋盘的同一行;
//(2)不在棋盘的同一列;
//(3)不在棋盘的同一对角线上。
//第一次输入:N
//第一次输出:共有多少组解
//第二次输入:输出第几组解
//第二次输出:以矩阵形式输出这一组解
#include <iostream>
#include <iomanip>
using namespace std;
int N;
int Normalize; //用来统一数组下标
int Num = 0; //方案数
int q[101]; //N个皇后所占用的行号,可是定义数组时下标不能是变量
//所以就暂估计一个较大的值N = 100吧
bool C[101]; //S[1]~S[N],当前列是否安全
bool L[201]; //L[2]~L[2 * N],(i - j)对角线是否安全
bool R[201]; //R[2]~R[2 * N],(i + j)对角线是否安全
int main()
{
for(int i = 0; i < 101; i++)
C[i] = true;
for(int i = 0; i < 201; i++)
{
L[i] = true;
R[i] = true;
}
cout << "请输入N:";
cin >> N;
Normalize = N + 1;
void Try(int row);
void Output(int row, int n);
Try(1); //从第1行开始放皇后
cout << "总共有" << Num << "组解!" << endl;
int x = 0;
cout << "请问需要输出第几组解?:";
cin >> x;
while(x > Num || x < 1)
{
cout << "数据越界!请重新输入!:";
cin >> x;
}
Num = 0; //Num重新置零,非常重要!
Output(1, x);
//cout << "Num = " << Num << endl;
return 0;
}
void Try(int row)
//除了对角线的处理外,N皇后问题的第二个技巧就是递归参数的选择,
//想一想,为什么没有选棋盘的规模N作为递归参数?而是选了行号或列号?
{
for(int col = 1; col <= N; col++)
//依次尝试当前的N列位置
{
//判断拟放置皇后的位置是否安全
if(C[col] && L[row - col + Normalize] && R[row + col])
{
//记录位置信息(行号)
q[row] = col;
//修改三个方向的安全性标记
C[col] = false;
L[row - col + Normalize] = false;
R[row + col] = false;
//核心技巧其实在后面这两行里,只有这样调整,对角线的下标才统一在一个相同的区间里
if(row < N)
{
//递归尝试放下一行
Try(row + 1);
}
else
{
Num++;
}
//回溯:恢复三个方向原有安全性
C[col] = true;
L[row - col + Normalize] = true;
R[row + col] = true;
}
}
}
void Output(int row, int n)
{
for(int col = 1; col <= N; col++)
//依次尝试当前的N列位置
{
//判断拟放置皇后的位置是否安全
if(C[col] && L[row - col + Normalize] && R[row + col])
{
//记录位置信息(行号)
q[row] = col;
//修改三个方向的安全性标记
C[col] = false;
L[row - col + Normalize] = false;
R[row + col] = false;
//核心技巧其实在后面这两行里,只有这样调整,对角线的下标才统一在一个相同的区间里
if(row < N)
{
//递归尝试放下一行,注意这里的函数是Output(),而不是Try()
Output(row + 1, n);
}
else
{
Num++;
if(Num == n)
{
cout << endl;
cout << "第" << n << "组解为:" << endl;
cout << endl;
cout << setiosflags(ios::right) << setw(4) << " ";
for(int i = 1; i <= N; i++)
cout << setiosflags(ios::right) << setw(4) << i;
cout << endl << endl;
for(int i = 1; i <= N; i++)
{
cout << setiosflags(ios::right) << setw(4) << char(65 + i - 1);
for(int j = 1; j <= N; j++)
{
if(j != q[i])
cout << setiosflags(ios::right) << setw(4) << '0';
else
cout << setiosflags(ios::right) << setw(4) << '1';
}
cout << endl << endl;
}
}
}
//回溯:恢复三个方向原有安全性
C[col] = true;
L[row - col + Normalize] = true;
R[row + col] = true;
}
}
}
以N = 15为例,输出结果如下!:
稍作修改后,N=16时的结果:(N=16可能是可以输出的最大值了,N=16也要算2分多钟才能算完,我的电脑CPU酷睿i5。N=17基本上算不出来,我等了五六分钟都没结果,具体需要多久算出来,可能要结合《计算机组成原理》中的知识。)