八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?
为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当 n = 1 或 n ≥ 4 时问题有解。
仔细分析此题,可以发现:如果我们从第一行开始放置,每行放置一个皇后,将要放置时,我们看有没有与前面的行上放置的皇后在同一列上或者同一对角线上(因为是一行一行的放置下来,所以行必然不会相同)。
所以用一个一维数组loc[i] 就可以存放在棋盘上放置的皇后的行列信息:loc[i]=j 表示在棋盘的第i行、第j列上放着一个皇后。
假设i行以前皇后的位置都已经确定,即loc[0~(i-1)]的值已知。
在进行第i行皇后放置时,从该行的第一个位置开始,对所有位置一次进行试探。
令loc[i]=j(即如果放在i行的第j个位置上),与前i-1个皇后不在同列,也没有在对角线上,可以进行下一行皇后的放置。
若冲突了,则右移一位,进行j+1位置的试探。
判断是否与前面的皇后在同列以及是否对角线也比较容易。
同列? 第1行到i-1行是否存在loc[i]=loc[x]?
对角线? i-x=abs(loc[i]-loc[x])?
【代码如下】
#include<iostream>
#include<cmath>
#define N 8//棋盘行列数,即皇后个数。
using namespace std;
int sum=0;//总的可能数。
bool check(int loc[],int x)//检查当前这种放置,判断可以这样放是否可行。
{
for(int i=0;i<x;i++)
{
//loc[i]==loc[x]进行列判断。
//abs(x-i)==abs(loc[x]-loc[i]) 是否在对角线上。
if(loc[i]==loc[x]||abs(x-i)==abs(loc[x]-loc[i]))
return false;
}
return true;
}
void show(int loc[])//显示放置皇后的棋盘
{
sum++;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(loc[i]==j)
cout<<" A ";
else
cout<<" - ";
}
cout<<endl;
}
}
void Queen(int loc[],int x)//loc[]存储已经放置的皇后坐标,x表示行。
{
if(x==N)//全部放完,已放到了最后一行。输出
{
show(loc);
cout<<endl<<endl;
return;
}
for(int i=0;i<N;i++)
{
loc[x]=i;//第x行,从0个位置到N-1 循环判断是否可以放置,
if(check(loc,x))
{
Queen(loc,x+1);//可以放,继续放下一行。
}
//不能放则右移一位,试探这一行的下一个位置;
}
}
int main()
{
int loc[N];//存储第i行皇后的位置
Queen(loc,0);//从0行开始放置。
cout<<sum<<endl;
}