问题描述:
在8*8的国际象棋棋盘上,要求在每一行(或者每一列)放置一个皇后,且能做到在水平方向、竖直方向和斜方向都没有冲突。请列出所有解法。
根据上述描述,我们可以得到如果两个皇后Q1(x, y)和Q2(row, col)不符合要求,则以下四个条件之一必符合。
1 ) x == row
2 ) y == col
3 ) x + y == row + col (斜向正方向)
4 ) x – y == row – col(斜向反方向)
归纳出了程序的判断条件,下面用主流的回溯法来解决N皇后问题,这里是8皇后问题。回溯法也就是带有剪枝的深度优先遍历。
用回溯的方法解决8皇后问题的步骤为:
1)从第一列开始,为皇后找到安全的一行,然后开始下一列
2)如果在第n列出现死胡同,则完全放弃后面所有列的搜索,直接后退到上一列,进行回溯
3)如果在第8列上找到了安全位置,则棋局成功。
8个皇后都找到了安全位置代表棋局的成功,用一个长度为8的整数数组colume代表成功摆放的8个皇后,数组索引代表棋盘的col向量,而数组的值为棋盘的row向量,所以(row,col)的皇后可以表示为(colume[col],col)
#include <iostream>
#include <cmath>
#define QUEEN_NUM 8
int ResultCounter = 0;
void printResult(int colume[]);
bool check(int colume[], int col);
void QueenSolution(int colume[], int col);
int main(void){
//数组colume中存放的是行值
//即假设col[0]==3,表明第1列中皇后在第4行上
int colume[QUEEN_NUM] = {0};
QueenSolution(colume, 0);
std::cout << "Solution Total Count: " << ResultCounter << std::endl;
}
//输出数组中的一组结果
void printResult(int colume[]){
for(int i = 0; i < QUEEN_NUM; i++)
std::cout << "(" << colume[i] << ", " << i << ") ";
std::cout << std::endl;
ResultCounter++;
}
//检查当前列col,在现有情况下,能否放置皇后
//如果是以下四种情况,就返回false
//1)x=row(在纵向不能有两个皇后)
//2) y=col(横向)
//3)col + row = y+x;(斜向正方向)
//4) col - row = y-x;(斜向反方向)
bool check(int colume[], int col){
//因为提供的是列信息,我们就逐列进行检查
for(int i = 0; i < col; i++)
{
if(colume[i] == colume[col] ||
std::abs(colume[i] - colume[col]) == col - i )
return false;
}
return true;
}
//尝试第col列上的所有解
//即在第col列的所有行上依次检验
//调用此函数时,表明从第0列到第col-1列都已经安置好了皇后
void QueenSolution(int colume[], int col){
if(col == QUEEN_NUM)
{
printResult(colume);
return;
}
//新的一列中,皇后有可能在任意一行
for(int i = 0; i < QUEEN_NUM; i++)
{
colume[col] = i; //将这个皇后放在第i行,进行检查
if( check(colume, col) )
QueenSolution(colume, col+1);
}
}
PS.结果为92个。