回溯算法----N皇后问题

回溯算法----N皇后问题

回溯算法一直都困扰我很长一段时间,看了回溯算法的视频,特地来写一下这个算法,加深印象。

回溯算法的通式

回溯算法有个通式。

void backtrack(){
    if(判断是否到头了){
        添加到vector里(一次正确的回溯结束,进行存储操作)
        return; 
    }
    for(){
        ...
        存储元素;
        backtrack;
        删除元素;
    }
}

当然这样写现在看不懂,往下看看回溯代码块就差不多了。

N皇后问题

N皇后问题指一个棋盘中,皇后Q所在的一行、一列、左斜线、右斜线都没有其他的皇后Q,这样组成的棋盘。具体题目可见leetcode51:

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

输入:n = 4

img

输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。

来源:力扣(LeetCode) 链接:力扣

解法

首先创造一个公共的vector容器,来存储答案。(个人习惯,也可以在backtrack中添加一个参数一直将res传递)

vector<vector<string>> ans;

然后创建一个棋盘:

vector<string> board(n,string(n,'.'));

回溯函数:

    void backtrack(vector<string>& board, int row){
        if(row == board.size()){
            ans.emplace_back(board);//一次回溯完成
            return;
        }

        for(int col = 0;col < board.size();col++){
            if(!isValid(board,row,col)){
                continue;
            }
            board[row][col] = 'Q';//存储元素
            backtrack(board,row+1);
            board[row][col] ='.';//删除元素
        }
    }

参数:

board是棋盘,需要对它进行操作,也是要传送到ans的vector。row是行,每次递归都需要将行数加1。

参数根据代码而定,本人也很难搞清究竟哪些来作为向下传递的参数。所以就哪些参数需要就传哪些。。。

存储与删除元素:

这里是存储与删除,其实笼统说是一直修改board,然后做完一整个回溯后,返回来对board维护,让board完好如初。

isValid是检查函数,由于是按行从上而下放置皇后Q的,所以,行不用检查,当前位置向下的列和斜线都不用检查。最终只需要检查上列,左上,右上。

    bool isValid(vector<string>& board,int row,int col){
        
        for(int i = 0;i < row;i++){
            if(board[i][col] == 'Q')//检查列
                return 0;
            if(col-row+i>=0){//检查左上
                if(board[i][col - row + i] == 'Q')
                    return 0;
            }
            if(col+row-i<board.size()){//检查右上
                if(board[i][col + row - i] == 'Q')
                    return 0;
            }
        }
        return 1;
    }

完整代码:

class Solution {
public:
    vector<vector<string>> ans;

    bool isValid(vector<string>& board,int row,int col){
        //检查列
        for(int i = 0;i < row;i++){
            if(board[i][col] == 'Q')
                return 0;
            if(col-row+i>=0){
                if(board[i][col - row + i] == 'Q')
                    return 0;
            }
            if(col+row-i<board.size()){
                if(board[i][col + row - i] == 'Q')
                    return 0;
            }
        }
        return 1;
    }

    void backtrack(vector<string>& board, int row){
        if(row == board.size()){
            ans.emplace_back(board);
            return;
        }

        for(int col=0;col<board.size();col++){
            if(!isValid(board,row,col)){
                continue;
            }
            board[row][col] = 'Q';
            backtrack(board,row+1);
            board[row][col] ='.';
        }
    }

    vector<vector<string>> solveNQueens(int n) {
        vector<string> board(n,string(n,'.'));
        backtrack(board,0);
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值