简介
“八皇后问题”是一个经典的算法问题,也是回溯算法的典型应用案例。它的目标是在一个8×8的国际象棋棋盘上放置八个皇后,使得任意两个皇后都不能互相攻击,即不能处于同一行、同一列或同一斜线上。
问题背景
- 提出:由德国数学家马克斯·贝瑟尔于 1848 年提出,后经高斯等数学家研究。
- 解的数量:高斯最初认为有 76 种解,后来通过图论方法确定共有 92 种不同的摆放方式。
- 扩展:该问题可推广为“n皇后问题”,即在n×n的棋盘上放置n个皇后,当n≥4时存在解。
解题思路
- 回溯算法:通过逐行放置皇后,并在每一步检查是否与已放置的皇后冲突。若冲突则回溯(撤销当前选择),尝试其他位置。
- 关键条件:
- 同一列不能有多个皇后。
- 同一斜线(斜率为±1)不能有多个皇后。
- 优化方法:使用位运算、对称性剪枝等技术减少计算量,例如利用位掩码表示列和对角线的占用情况。
C 语言代码实现
#include <stdio.h>
#include <stdlib.h>
#define MAX_QUEENS 8
int queen[MAX_QUEENS] = {-1}; // 记录每行皇后的列位置,初始化为-1
int count = 0; // 解的总数
// 检查当前位置(row, col)是否安全
int is_safe(int row, int col)
{
for (int i = 0; i < row; i++)
{
// 同一列或同一斜线
if (queen[i] == col || abs(queen[i] - col) == row - i)
{
return 0;
}
}
return 1;
}
// 回溯函数,从第row行开始放置皇后
void backtrack(int row)
{
if (row == MAX_QUEENS)
{ // 找到一个解
printf("Solution %d:\n", ++count);
for (int i = 0; i < MAX_QUEENS; i++)
{
for (int j = 0; j < MAX_QUEENS; j++)
{
if (queen[i] == j)
{
printf("Q ");
}
else
{
printf("* ");
}
}
printf("\n");
}
printf("\n");
return;
}
// 尝试每一列
for (int col = 0; col < MAX_QUEENS; col++)
{
if (is_safe(row, col))
{
queen[row] = col; // 放置皇后
backtrack(row + 1); // 递归下一行
queen[row] = -1; // 回溯,撤销当前位置
}
}
}
int main()
{
backtrack(0);
printf("Total solutions: %d\n", count);
return 0;
}
应用与意义
- 算法教学:常用于理解回溯、递归和剪枝策略。
- 问题扩展:启发类似布局优化问题,如资源调度、路径规划等。
- 计算挑战:早期被用于测试计算机性能,如今仍是算法研究的经典案例。
如果需要更深入的实现细节或优化方法,大家可以一起探讨哦!
附上输出结果:
Solution 1:
Q * * * * * * *
* * * * Q * * *
* * * * * * * Q
* * * * * Q * *
* * Q * * * * *
* * * * * * Q *
* Q * * * * * *
* * * Q * * * *
Solution 2:
Q * * * * * * *
* * * * * Q * *
* * * * * * * Q
* * Q * * * * *
* * * * * * Q *
* * * Q * * * *
* Q * * * * * *
* * * * Q * * *
...
Solution 92:
* * * * Q * * *
* * Q * * * * *
* * * * * * Q *
Q * * * * * * *
* * * * * Q * *
* * * * * * * Q
* Q * * * * * *
* * * Q * * * *
Total solutions: 92