问题:国际象棋中的皇后,可以横向、纵向、斜向移动。如何在一个8X8的棋盘上放置8个皇后,使得任意两个皇后都不在同一条横线、竖线、斜线方向上?
思路:
使用递归回溯的方式。
所谓递归回溯,本质上是一种枚举法。这种方式从棋盘的第一行开始尝试摆放第一个皇后,摆放成功后,递归一层,再遵循规则在棋盘第二行来摆放第二个皇后。如果当前位置无法摆放,则向右移动一格再次尝试,如果成功,则继续递归一层,摆放第三个皇后……
如果某一层看遍了所有格子,都无法成功摆放,则回溯到上一个皇后,让上一个皇后右移一格,再进行递归。如果八个皇后都摆放完毕且符合规则,那么就得到了其中一种解法。
解决八皇后问题,可以分为两个层面:
1.找出第一种正确摆放方式,也就是深度优先遍历。
2.找出全部的正确摆放方式,也就是广度优先遍历。
深度优先遍历:
#include <iostream>
#include <string>
using namespace std;
//棋盘格子的范围,以及皇后数量
const int MAX_NUM = 8;
//二维数组作为棋盘
int chessBoard[MAX_NUM][MAX_NUM] = {0};
//检查落点是否符合规则
bool check(int x, int y)
{
for (int i = 0; i < y; i++)
{
//检查纵向
if (chessBoard[x][i] == 1)
return false;
//检查左侧斜向
if (x - 1 - i >= 0 && chessBoard[x - 1 - i][y - 1 - i] == 1)
return false;
//检查右侧斜向
if (x + 1 + i < MAX_NUM && chessBoard[x + 1 + i][y - 1 - i] == 1)
return false;
}
return true;
}
//递归回溯
bool settleQueen(int y)
{
//行数超过8,说明已经找出答案
if (y == MAX_NUM)
return true;
//遍历当前行,逐一格子验证
for (int i = 0; i < MAX_NUM; i++)
{
//为当前行清零,以免回溯时出现脏数据
for (int x = 0; x < MAX_NUM; x++)
{
chessBoard[x][y] = 0;
}
//检查是否符合规则,如果符合,更改元素值并进一步递归
if (check(i, y))
{
chessBoard[i][y] = 1;
//递归如果返回true,说明下层已找到解法,无需继续循环
if (settleQueen(y + 1))
return true;
}
}
return false;
}
void printChessBoard()
{
for (int j = 0; j < MAX_NUM; j++)
{
for (int i = 0; i < MAX_NUM; i++)
{
cout << chessBoard[i][j];
}
cout << endl;
}
}
int main()
{
settleQueen(0);
printChessBoard();
system("pause");
return 0;
}