1. 程式人生 > 其它 >LeetCode/N皇后

LeetCode/N皇后

n皇后問題研究的是如何將n個皇后放置在n×n的棋盤上並且使皇后彼此之間不能相互攻擊。
要求:任何兩個皇后不同行,不同列也不在同一條斜線上,
給你一個整數n,返回所有不同的n皇后問題的解決方案。
每一種解法包含一個不同的n皇后問題 的棋子放置方案,該方案中 'Q' 和 '.' 分別代表了皇后和空位

思路
使用回溯演算法,試探路徑,核心在於for迴圈裡面做遞迴,在遞迴呼叫之前做選擇,在遞迴之後撤銷選擇,具體回溯框架如下

def backtrack(路徑,選擇列表)
    if 滿足結束條件:
        result.add(路徑)
        return 
    for 選擇 in 選擇列表:
        做選擇
        backtrack(路徑,選擇列表)
        撤銷選擇

在N皇后問題中,回溯具體過程為,該行從任意一列中選擇一個棋子,判斷該路徑是否滿足要求,滿足要求繼續遞迴進入下一行,遞迴結束後撤銷上一步選擇,進行上一行其他列的選擇,每一次遞迴結束意為著到達邊界

點選檢視程式碼
class Solution {
public:
    vector<vector<string>> res;//儲存最終結果
    vector<vector<string>> solveNQueens(int n) {
        vector<string> board(n,string(n,'.'));//初始化棋盤,全為空
        backtrack(board,0);
        return res;
    }
//路徑:board中小於row的那些行都已經放置
//選擇列表:第row行所有列都可以作為選擇
//結束條件:row超過board最後一行
    void backtrack(vector<string>& board,int row){
        //觸發結束條件
        if(row == board.size()){
            res.push_back(board);//結束後將該棋盤佈局新增至結果
            return;
        }

        int n = board[row].size();//避免重複計算
        for(int col = 0; col < n; col++){
            //排除不合法選擇
            if(!isValid(board,row,col))
                continue;
            //做選擇
            board[row][col]='Q';
            //進入下一行決策
            backtrack(board,row+1);
            //撤銷選擇
            board[row][col]='.';//撤銷選擇是為了進入該行的下一個選擇
        }
    }
    bool isValid(vector<string>& board,int row,int col){
        int n = board[row].size();
        //檢查列是否衝突
        for(int i=0;i<n;i++){
            if(board[i][col] =='Q') return false;
        }
        //檢查右上方衝突
        for(int i=row-1,j=col+1;i>=0&&j<n;i--,j++){
            if(board[i][j] =='Q') return false;
        }
        //檢查左上方衝突
        for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
            if(board[i][j] =='Q') return false;
        }
        return true;        
    }
};