-
N皇后
- 題目描述
n 皇后問題研究的是如何將 n 個皇后放置在 n×n 的棋盤上,並且使皇后彼此之間不能相互攻擊。
上圖爲 8 皇后問題的一種解法。
給定一個整數 n,返回所有不同的 n 皇后問題的解決方案。每一種解法包含一個明確的 n 皇后問題的棋子放置方案,該方案中 'Q' 和 '.' 分別代表了皇后和空位。
- 思路
回溯中最經典的問題。這裏簡單總結下回溯的寫法:
首先,通常需要一個記錄所有滿足條件結果的容器,在下面的代碼中就是參數res;
其次,需要一個容器來記錄當前回溯的路徑,在下面的代碼中就是參數nQueens;
最後,就是需要記錄當前搜索的位置,即row;以及終止條件,即n;
該題目中沒有剪枝條件,但是回溯有時會遇到需要剪枝的情況;
詳細的理解,請見下方代碼:
- C++實現
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<string> nQueens(n,string(n,'.')); //n個字符串,每個字符串是n個'.'組成
solveNQueens(res, nQueens, 0, n);
return res;
}
/**
res:用於存儲所有的解決方案
nQueens:用於存儲當前的解決方案
row:當前解決方案所掃描的行
n:行/列數
**/
void solveNQueens(vector<vector<string>> &res,
vector<string> &nQueens,int row,int n){
if(row==n){//row的合理位置在[0,n-1],當其爲n時表示已經掃描完整個棋盤
res.push_back(nQueens);
return;
}
for(int col = 0;col<n;col++){
if(isValid(nQueens,row,col,n)){
nQueens[row][col] = 'Q'; //放置皇后
solveNQueens(res, nQueens, row + 1, n);
nQueens[row][col] = '.'; //還原
}
}
}
bool isValid(vector<string> &nQueens, int row, int col, int n){
// 檢查當前列在先前的行中是否已經放置了Q
for (int i = 0; i<row; ++i)
if (nQueens[i][col] == 'Q')
return false;
// 檢查前面的45度角
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j)
if (nQueens[i][j] == 'Q')
return false;
// 檢查前面的135度角
for (int i = row - 1, j = col + 1; i >= 0 && j < n; --i, ++j)
if (nQueens[i][j] == 'Q')
return false;
return true;
}
};
-
N皇后II
- 題目描述
類似於上面的題目,只不過變爲返回可能的方案數量,而不是所有的方案。
- 思路
類似於上面的題目,只不過不需要記錄所有的方案,因此不需要res,只使用整型變量count來記錄結果。
- C++實現
class Solution {
public:
int totalNQueens(int n) {
int count = 0;
vector<string> nQueens(n,string(n,'.'));
solveNQueens(count,nQueens,0,n);
return count;
}
// &n?
void solveNQueens(int& count,vector<string> nQueens,int row,int n){
if(row==n){//終止條件
count++;
return;
}
for(int col=0;col<n;col++){
if(isValid(nQueens,row,col,n)){
nQueens[row][col] = 'Q'; // 放置皇后
solveNQueens(count, nQueens, row + 1, n);
nQueens[row][col] = '.'; // 還原
}
}
}
bool isValid(vector<string> &nQueens, int row, int col, int n){
// 檢查當前列在先前的行中是否已經放置了Q
for (int i = 0; i<row; ++i)
if (nQueens[i][col] == 'Q')
return false;
// 檢查前面的45度角
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j)
if (nQueens[i][j] == 'Q')
return false;
// 檢查前面的135度角
for (int i = row - 1, j = col + 1; i >= 0 && j < n; --i, ++j)
if (nQueens[i][j] == 'Q')
return false;
return true;
}
};