八皇后问题一共有92种不同的摆放方法。按照前面对四皇后问题的讨论,摆放时按行的顺序进行,因此只需考虑列和对角线的问题。
为了讨论皇后问题摆放的可行性,程序中使用到的三个数组C[j] 、R[m]和L[k] 都为布尔型且初始化时全部置为true。其中i为行号,j为列号,i,j=1,2,…8;m=i+j,m=2,3,…16;k=i-j+9,k=2,3,…16。右上至左下的对角线是否可行,取决于R[m]为true或false;而左上至右下的对角线是否可行,取决于L[k]为true或false。这样可以令
L(i-j+9)=false
L(i+j)=true
来表示在(i,j)位置摆放皇后之后,通过该位置的两条对角线上不可行了。这样得出在(i,j)位置可摆放皇后的可行条件是:
nQueen=C[j] &&R[i+j]&&L[i-j+9]
其中i-j+9是为了避免数组下标为负值,再有就是为了使L数组和R数组的下标上下界一致,均为2,3,….,16。
在摆放第i个皇后时(当然在第i行),选择第j列,当nQueen为true时,就可将皇后摆放在(i,j)位置。如果Queen[i]=j,则同时使得第j列和过(i,j)位置的两条对角线变为不可行,即C[j]=false,R[i+j]=false,L[i-j+9]=false;之后检查i是否为8,如果为8则表明已经放完8个皇后,这时让方案数Num加1,输出该方案下8个皇后在棋盘上的位置,如果未到8个,则要让皇后数i加1再尝试摆放,这时递归调用check(i+1);如果方案不可行,则需要回溯,将前面摆放的皇后从棋盘上拿起,看看还有没有可能换一处位置摆放,这时要将被拿起的皇后的所在位置的第j列和两条对角线恢复为可行。
#include<iostream>
using namespace std;
const int Normalize=9; //定义常量,用来统一数组下标
int Num=0; //整型变量,记录方案数
int Queen[9]; //记录8个皇后所占用的列号
bool C[9]; //C[1]~C[8]布尔型变量,判断当前列是否可行
bool L[17]; //L[2]~L[16]布尔型变量,判断(i-j)对角线是否可行
bool R[17]; //R[2]~R[16]布尔型变量,判断(i+j)对角线是否可行
void check(int i) //被调用函数
{
int j; //循环变量,表示列号
int k; //临时变量
for(j=1;j<=8;j++)
{
if((C[j]==true) &&(R[i+j]==true)&&(L[i-j+Normalize]==true))
//表示第i行第j列可行
{
Queen[i]=j; //占用位置(i,j)
C[j]=false; //修改可行标志,包括所在列和两个对角线
L[i-j+Normalize]=false;
R[i+j]=false;
if(i<8) //判断是否放完8个皇后
{
check(i+1); //未放完8个皇后则继续放下一个
}
else //已经放完8个皇后
{
Num++; //方案数加1
cout<<"方案"<<Num<<":"<<"\t";//输出方案号
for(k=1;k<=8;k++)
cout<<k<<"行"<<Queen[k]<<"列"<<"\t";//输出具体方案
cout<<endl; //换行
}
C[j]=true; //修改可行标志,回溯
L[i-j+Normalize]=true;
R[i+j]=true;
} //循环结束
}
} //check函数结束
int main() //主函数
{
int i; //循环变量
Num=0; //方案数清零
for(i=1;i<9;i++) //置所有列可行
C[i]=true;
for(i=0;i<17;i++) //置所有对角线可行
L[i]=R[i]=true;
check(1); //递归放置8个皇后,从第一行开始放
return 0;
}