问题简介
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。
参考资料: 八皇后问题-百度百科
由问题的条件可知,符合条件的放置方法必然每一行或每一列存在一个皇后。所以将用递归方法,逐行逐点尝试放置皇后棋子。在放置每一行的皇后时,只要考虑到之前行的皇后能不能攻击到目标点。由于运用了递归,可在每一行逐点尝试放置皇后棋子,直到最后成功放置最后一行的皇后。
实现代码:
//输出与统计符合条件的棋盘排列
void PrintCheckerBoard(int checkerBoard[8][8]) {
static int times = 0;//静态变量用于统计情况个数
times++;
printf("第%d种情况:\n", times);
for (int x = 0; x < 8; x++) {
printf("---------------------------------\n");
for (int y = 0; y < 8; y++) {
if (checkerBoard[x][y] == 1)printf("| * ");
else printf("| ");
}
printf("|\n");
}
printf("---------------------------------\n");
printf("\n\n");
}
//检查目标点是否符合皇后放置条件(若符合返回0,不符合返回1)
int CheckPoint(int checkerBoard[8][8], int x, int y) {
//由于是逐层放置,检查目标点所在层前相应位置是否有棋子
for (int i = 0; i < x; i++) {
//检查目标点所在列上方是否有棋子
if (checkerBoard[i][y]) return 1;
}
int i = 1;
while (x - i >= 0 && y - i >= 0) {
//检查目标点左斜上方是否有棋子
if (checkerBoard[x - i][y - i])
return 1;
i++;
}
i = 1;
while (x - i >= 0 && y + i < 8) {
//检查目标点右斜上方是否有棋子
if (checkerBoard[x - i][y + i])
return 1;
i++;
}
return 0;
}
//问题解决使用的递归函数
void EightQueensProblem(int checkerBoard[8][8], int x) {
for (int y = 0; y < 8; y++) {//尝试放置当前层的每一个位置
if (CheckPoint(checkerBoard, x, y))continue;
//如果该位置不符合要求,则直接进入下一循环
checkerBoard[x][y] = 1;
//在当前位置放置皇后棋子
if (x == 7)PrintCheckerBoard(checkerBoard);
//如果放置的棋子在最后一层,则输出当前放置情况
else EightQueensProblem(checkerBoard, x + 1);
//若不是最后一层,则进行下一层的放置
checkerBoard[x][y] = 0;
//移除当前位置的皇后棋子,以进行下一位置的放置
}
}
//问题实现函数
void Play() {
int *checkerBoard = (int *)malloc(sizeof(int) * 8 * 8);
//申请空间作为棋盘的数据结构
for (int i = 0; i < 64; i++)*(checkerBoard + i) = 0;
//初始化棋盘
EightQueensProblem(checkerBoard, 0);
//调用递归解决问题
system("pause");
}
void main(void) {
Play();
return;
}