W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
Question
根據(jù)國際象棋的規(guī)則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。給定
如圖 13-15 所示,當(dāng) choices
。在逐個(gè)放置皇后的過程中,棋盤狀態(tài)在不斷地變化,每個(gè)時(shí)刻的棋盤就是狀態(tài) state
。
圖 13-15 4 皇后問題的解
圖 13-16 展示了本題的三個(gè)約束條件:多個(gè)皇后不能在同一行、同一列、同一對角線。值得注意的是,對角線分為主對角線 \
和次對角線 /
兩種。
圖 13-16 n 皇后問題的約束條件
皇后的數(shù)量和棋盤的行數(shù)都為
也就是說,我們可以采取逐行放置策略:從第一行開始,在每行放置一個(gè)皇后,直至最后一行結(jié)束。
如圖 13-17 所示,為
圖 13-17 逐行放置策略
本質(zhì)上看,逐行放置策略起到了剪枝的作用,它避免了同一行出現(xiàn)多個(gè)皇后的所有搜索分支。
為了滿足列約束,我們可以利用一個(gè)長度為 cols
記錄每一列是否有皇后。在每次決定放置前,我們通過 cols
將已有皇后的列進(jìn)行剪枝,并在回溯中動(dòng)態(tài)更新 cols
的狀態(tài)。
那么,如何處理對角線約束呢?設(shè)棋盤中某個(gè)格子的行列索引為
也就是說,如果兩個(gè)格子滿足 diag1
,記錄每條主對角線上是否有皇后。
同理,次對角線上的所有格子的 diag2
來處理次對角線約束。
圖 13-18 處理列約束和對角線約束
請注意,diag1
和 diag2
的長度都為
n_queens.cpp
/* 回溯算法:N 皇后 */
void backtrack(int row, int n, vector<vector<string>> &state, vector<vector<vector<string>>> &res, vector<bool> &cols,
vector<bool> &diags1, vector<bool> &diags2) {
// 當(dāng)放置完所有行時(shí),記錄解
if (row == n) {
res.push_back(state);
return;
}
// 遍歷所有列
for (int col = 0; col < n; col++) {
// 計(jì)算該格子對應(yīng)的主對角線和副對角線
int diag1 = row - col + n - 1;
int diag2 = row + col;
// 剪枝:不允許該格子所在列、主對角線、副對角線存在皇后
if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
// 嘗試:將皇后放置在該格子
state[row][col] = "Q";
cols[col] = diags1[diag1] = diags2[diag2] = true;
// 放置下一行
backtrack(row + 1, n, state, res, cols, diags1, diags2);
// 回退:將該格子恢復(fù)為空位
state[row][col] = "#";
cols[col] = diags1[diag1] = diags2[diag2] = false;
}
}
}
/* 求解 N 皇后 */
vector<vector<vector<string>>> nQueens(int n) {
// 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位
vector<vector<string>> state(n, vector<string>(n, "#"));
vector<bool> cols(n, false); // 記錄列是否有皇后
vector<bool> diags1(2 * n - 1, false); // 記錄主對角線是否有皇后
vector<bool> diags2(2 * n - 1, false); // 記錄副對角線是否有皇后
vector<vector<vector<string>>> res;
backtrack(0, n, state, res, cols, diags1, diags2);
return res;
}
逐行放置
數(shù)組 state
使用 cols
、diags1
和 diags2
皆使用
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: