知识点:全排列问题与N皇后问题都是两个经典的回溯算法的例子。
回溯算法是有一个基本的框架流程。
看到的一个特别详细的回溯算法博客:https://leetcode-cn.com/problems/n-queens/solution/hui-su-suan-fa-xiang-jie-by-labuladong/
N皇后问题:给你一个 N×N 的棋盘,让你放置 N 个皇后,使得它们不能互相攻击。
PS:皇后可以攻击同一行、同一列、左上左下右上右下四个方向的任意单位。
这个问题本质上跟全排列问题差不多,决策树的每一层表示棋盘上的每一行;每个节点可以做出的选择是,在该行的任意一列放置一个皇后。
作者:labuladong
链接:https://leetcode-cn.com/problems/n-queens/solution/hui-su-suan-fa-xiang-jie-by-labuladong/
来源:力扣(LeetCode)
class Solution {
public:
vector<vector<string>> res; //定义返回变量res是个二维数组形式
vector<vector<string>> solveNQueens(int n) {
vector<string> board(n, string(n, '.'));//创建一个一维形式的棋盘,并初始化为空棋盘
backtrack(board, 0);
return res;
}
// 路径:board 中小于 row 的那些行都已经成功放置了皇后
// 选择列表:第 row 行的所有列都是放置皇后的选择
// 结束条件:row 超过 board 的最后一行
/*回溯算法框架 */
void backtrack(vector<string>& board, int row) {
// 触发结束条件
if (row == board.size()) {
res.push_back(board); //如果满足结束条件,将路径添加到返回结果中
return;
}
int n = board[row].size();//列数
for (int col = 0; col < n; col++) {//for 选择 in 选择列表
// 排除不合法选择
if (!isValid(board, row, col))
continue;
// 做选择
board[row][col] = 'Q';//将该选择从选择列表移除,而添加到路径中
// 进入下一行决策
backtrack(board, row + 1);
// 撤销选择
board[row][col] = '.';//是将该选择从路径里面移除,【而重新添加到选择列表中】
}
}
/* 是否可以在 board[row][col] 放置皇后? */
bool isValid(vector<string>& board, int row, int col) {
int n = board.size();//行数
// 检查列是否有皇后互相冲突
for (int i = 0; i < n; i++) {
if (board[i][col] == 'Q')
return false;
}
// 检查右上方是否有皇后互相冲突
for (int i = row - 1, j = col + 1;
i >= 0 && j < n; i--, j++) {
if (board[i][j] == 'Q')
return false;
}
// 检查左上方是否有皇后互相冲突
for (int i = row - 1, j = col - 1;
i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q')
return false;
}
return true;
}
};