51 N皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
解法 回溯法
N皇后要注意两个皇后不能同时出现在同一行、同一列、同一左斜线和同一右斜线。同一行可在递归时完成记录,不需要额外的容器记录,同一列、左斜线和右斜线都是需要容器专门去记录,可以观察到斜线容器的长度为2 * n - 1
;
左斜线对应关系:row + col
;
右斜线对应关系:n - row + col - 1
;
如果if(col[i] || ldiag[row + i] || rdiag[total - row + i - 1])
有一个为真,则说明该列、左斜线或者右斜线上存在一个皇后,则当前皇后一定无法放置在这个位置,就需要继续对下一列进行判断;
如果全为假,则说明当前皇后可以放置在这个地方,并把这一列、左斜线、右斜线位置设为true
,防止其他皇后放入,进入下一轮的递归,直到所有皇后都找到了自己的放置位置!
附完整代码:
class Solution {
public:
vector<vector<string>> ans;
vector<string> res;
bool solved;
void backtrack(vector<bool>& col, vector<bool>& ldiag, vector<bool>& rdiag, int total, int row){
if(row == total){
ans.push_back(res);
return;
}
else{
for(int i = 0; i < total; ++i){
if(col[i] || ldiag[row + i] || rdiag[total - row + i - 1]){
continue;
}
//符合条件 放置皇后
res[row][i] = 'Q';
col[i] = ldiag[row + i] = rdiag[total - row + i - 1] = true;
backtrack(col, ldiag, rdiag, total, row + 1);
//回溯 拿走当前位置上的皇后
col[i] = ldiag[row + i] = rdiag[total - row + i - 1] = false;
res[row][i] = '.';
}
}
}
vector<vector<string>> solveNQueens(int n) {
res.resize(n, string(n, '.'));
vector<bool> col(n, false), ldiag(2 * n - 1, false), rdiag(2 * n - 1, false);
solved = false;
backtrack(col, ldiag, rdiag, n, 0);
return ans;
}
};
解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
题解 回溯法
数独只有唯一解,可以设置一个标志,表示问题当前是否被解决,如果已经被解决就不需要在继续递归。
同样设置三个标志容器,分别用来检验行,列,三行三列组成的小块是否满足条件!与N皇后大同小异!
需要注意的可能是坐标到容器位置的一个映射关系:
class Solution {
public:
bool row[9][9];
bool col[9][9];
bool block[9][9];
bool solved;
vector<pair<int, int>> vec;
void dfs(vector<vector<char>>& board, int pos){
if(pos == vec.size()){
solved = true;
return;
}
auto [i, j] = vec[pos];
for(int digit = 0; digit < 9 && !solved; ++digit){
if(!row[i][digit] && !col[j][digit] && !block[i / 3 * 3 + j / 3][digit]){
board[i][j] = digit + '0' + 1;
row[i][digit] = col[j][digit] = block[i / 3 * 3 + j / 3][digit] = true;
dfs(board, pos + 1);
row[i][digit] = col[j][digit] = block[i / 3 * 3 + j / 3][digit] = false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(row, false, sizeof(row));
memset(col, false, sizeof(col));
memset(block, false, sizeof(block));
solved = false;
for(int i = 0; i < 9; ++i){
for(int j = 0; j < 9; ++j){
if(board[i][j] == '.'){
vec.emplace_back(i, j);
}
else{
char num = board[i][j];
row[i][num - '1'] = col[j][num - '1'] =
block[i / 3 * 3 + j / 3][num - '1'] = true;
}
}
}
dfs(board, 0);
}
};