n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。即使其中任意两个皇后都不同列、同行和在一条斜线上。
本题用回溯法解决,基本思想为采用深度优先遍历策略,遍历过程中对于每个节点做一次判断,如果满足约束条件则继续向下,否则回溯到前置节点。达到最大深度时则可得到其中一种问题的解。
回溯模板
vector<bool> judge(n);//记录列表
void backtrack(int x)
{
if (x == n)
{
//得到问题的其中一个解
......
//返回
return;
}
for (int i = begin, i != end; ++i) //begin为上界,end为下界
{
if (cheak(x, i)) //如果满足约束条件
{
//做出记录等其它操作
judge[x] = true;
......
//向里探索
backtrack(i)
//撤销记录等其它操作
judge[x] = false;
......
}
}
}
例题: N皇后
思路: 注意到 对于棋盘上的每一个位置
行 + 列 = 常数
行 - 列 = 常数
所以每一个位置所在的列,主对角线,副对角线都是唯一的,可以按行循环,col,mains,sub作为记录。
解题代码:
class Solution
{
public:
vector<int> col, mains, sub;//记录列表
vector<vector<string>> ans;
void backtrack(vector<string>& f, int row, int n)
{
if (row == n)
{
ans.push_back(f);//得到一个解
return;
}
for (int c = 0; c < n; ++c)
{
if (!col[c] && !mains[row-c+n-1] && !sub[row + c])//cheak
{
// 记录
f[row][c] = 'Q';
col[c] = mains[row-c+n-1] = sub[row + c] = 1;
//向里探索
backtrack(f, row + 1, n);
//取消记录
f[row][c] = '.';
col[c] = mains[row-c+n-1] = sub[row + c] = 0;
}
}
return;
}
vector<vector<string>> solveNQueens(int n)
{
col.resize(n);
mains.resize(2*n - 1);
sub.resize(2*n - 1);
vector<string> f(n, string(n, '.'));
backtrack(f, 0, n);
return ans;
}
};