八皇后问题是计算机科学中最为经典的问题之一,该问题由国际西洋棋棋手马克斯·贝瑟尔于1848年提出。八皇后问题,即在8×8的国际象棋盘上摆放八个皇后,使其不能互相攻击,任意两个皇后都不能处于同一行、同一列或同一斜线上,求出一共有多少种摆放方式,每种摆放方式的具体摆法。
#include <stdio.h>
#include <vector>
#include <string>
using namespace std;
// 放置皇后的位置,并标记攻击范围
void put_queen(int x, int y, vector<vector<int>> &attack)
{
static const int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1};
static const int dy[] = {0, 0, -1, 1, -1, 1,-1, 1};
attack[x][y] = 1; //将皇后位置标记为1
//通过两层for循环,将该皇后可能攻击到的位置进行标记
for (int i = 1; i < attack.size(); i++) // 从皇后位置向1到n-1个距离延伸
{
for (int j = 0; j < 8; j++) // 遍历皇后周围的8个方向
{
int nx = x + i * dx[j]; // 生成的新的位置行
int ny = y + i * dy[j]; // 生成的新的位置列
// 攻击的位置在棋盘范围内
if (nx >= 0 && nx < attack.size() && ny >= 0 && ny < attack.size())
{
attack[nx][ny] = 1; // 将新位置标记为1
}
}
}
}
// 回溯法求解N皇后的递归函数
// k表示当前处理的行
// n表示N皇后问题
// queen存储皇后的位置
// attack标记皇后的攻击位置
// solve存储N皇后的全部解法
void backtrack(int k, int n, vector<string> &queen,
vector<vector<int>> &attack, vector<vector<string>> &solve)
{
if (k == n) //是否完成一种摆放法,递归结束的条件, 找到一组解
{
solve.push_back(queen); // 将结果queue存储至solve
return;
}
// 遍历0至n-1列, 在循环中,回溯试探皇后可以放置的位置
for (int i = 0; i < n; i++)
{
if (attack[k][i] == 0) // 判断当前第K行第i列是否可以放置皇后
{
vector<vector<int>> tmp = attack; // 备份attack数组
queen[k][i] = 'Q'; // 标记该位置为“Q”
put_queen(k, i, attack); // 更新attack数组
backtrack(k + 1, n, queen, attack, solve); // 递归试探k+1行的皇后位置
// 找不到能放置皇后的位置或者完成一次成功摆放,在这里回溯
attack = tmp; //恢复attack数组
queen[k][i] = '.'; // 恢复queen数组
}
}
}
vector<vector<string>> solveNQueens(int n)
{
vector<vector<string>> solve; // 存储最后结果
vector<vector<int>> attack; // 标记皇后攻击位置
vector<string> queen; // 保存皇后位置
// 使用循环初始化attack和queen数组
for (int i = 0; i < n; i++)
{
attack.push_back(std::vector<int>());
for (int j = 0; j < n; j++)
{
attack[i].push_back(0);
}
queen.push_back(" ");
queen[i].append(n, '.');
}
backtrack(0, n, queen, attack, solve); // 调用backtrack求解N皇后问题
return solve; // 返回结果数组solve
}
int main()
{
vector<vector<string>> result;
result = solveNQueens(8);
printf("8皇后共有%d种解法\n\n", result.size());
for (int i = 0; i < result.size(); i++)
{
printf("解法%d:\n", i);
for (int j = 0; j < result[i].size(); j++)
{
printf("%s\n", result[i][j].c_str());
}
printf("\n");
}
return 0;
}
引用自
https://www.bilibili.com/video/BV1ZK411K7A8?share_source=copy_web