Lintcode 33. N皇后问题
题目描述:将n个皇后放在n*n
棋盘上,当任何两个皇后不在同一行、同一列、同一对角线上时,这样两个皇后就不会相互攻击。
给定一个整数n
,要求返回在n*n
棋盘上摆放n个皇后且不产生相互攻击的的所有摆放方案。
每个解决(摆放)方案都是包含n个皇后的不同的摆放位置的棋盘样式(参看下方样例),其中’Q’和’.'分别表示一个皇后和一个空白空间。
解题思路:因为皇后的摆放方法要求同一行和同一列只能有一个,比如,如果你已经之前在第1列摆放过,那下一次只能在除1之外的2,3,4…进行摆放乐,因此每一种摆放方法其实都是其中的一种排列,比如上面样例2中的方案一代表排列2413,方案二代表排列3142。所以这道题其实是排列问题。但是它也不是将所有的排列方案全都返回,因为一些是不满足要求的(如果两个皇后处于同一行、同一列、同一对角线上,就不满足条件),所以需要找的时候过滤掉这些不满足条件的方案。
同一行同一列的条件要判断,但是同一对角线呢?
从图中可以看出,从左上到右下满足横纵坐标之差相等,从右上到左下满足横纵坐标之和相等,代码实现时将这两种对角线的情况排除掉。
class Solution {
public:
/*
* @param n: The number of queens
* @return: All distinct solutions
*/
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> result;
vector<int> col;//用于存放每个皇后所在的列
search(n, col, result);
return result;
}
//1. 递归的定义
void search(int n, vector<int> &col, vector<vector<string>> &result) {
//3. 递归的出口
if (col.size() == n) {
result.push_back(drawChessLine(col, n));
return;
}
//2. 递归的拆解
for (int now_col = 0; now_col < n; ++now_col) {
if (!isValid(col, now_col)) {
continue;
}
col.push_back(now_col);
search(n, col, result);//递归语句上下保持对称
col.pop_back();
}
}
//对皇后摆放的位置(列)进行合法性判断, now_col为当前列,col为已经摆放好的列
bool isValid(vector<int> &col, int now_col) {
int now_row = col.size();//与now_col对应的当前行
for (int rowIdx = 0; rowIdx < col.size(); ++rowIdx) {
// 与之前的排放位置处于同一行或同一列的情况
if (col[rowIdx] == now_col) {
return false;
}
// 从右上到左下
if (rowIdx + col[rowIdx] == now_row + now_col) {
return false;
}
// 从左上到右下
if (rowIdx - col[rowIdx] == now_row - now_col) {
return false;
}
}
return true;
}
// 将找到的皇后排放位置的数组排列整理为满足题目要求棋盘形式中的一行["..Q."]
vector<string> drawChessLine(vector<int> &col, int n) {
vector<string> result;
for (int i = 0; i < n; ++i) {
string tmp(n, '.');
tmp[col[i]] = 'Q';
result.push_back(tmp);
}
return result;
}
};