leetcode 51-52 N皇后

题目描述:

n行n列的棋盘上放n个皇后,已知皇后之间不能同行、同列、同对角线,任意给定正整数n,求放置的方法与解决方案数量。

示例:

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

算法思想:

典型的深度优先搜索例题。对于深度优先遍历,重要的是想清楚搜索的顺序。八皇后问题中,已知皇后之间不能同行,所以 按行枚举,则只需要记录每行皇后放置的列号即可。
则问题转变为枚举n列的全排列问题,类似 leetcode46 全排列的做法,对列号进行全排列,即可得到每个解决方案的列号,从而安要求解决问题。

c++代码示例:
class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        this->n = n; // 设置全局变量n = n;
        used = vector<bool>(n,false); // 标记列有没有用过初始化。
        dfs(0);
        vector<vector<string>> result; // 将ans中存储的每个解决方案中列号转化为题意要求的字符。
        for(auto per : ans){
            vector<string> res; // 定义中间字符串数组
            for(int row = 0; row < n; row++){
                string s(n,'.'); // 临时对象s初始化为 n 个'.'
                int col = per[row]; // 记录对应列号,将其标记为'Q'
                s[col] = 'Q';
                res.push_back(s);
            }
            result.push_back(res);
        }
        return result;
    }

    void dfs(int u){
        if(u == n){
            ans.push_back(set);
            /*
            	for(auto x:set) cout << x << ' ';
            	cout << endl; 
            */
            return;
        }
        for(int i = 0; i < n; i++){
            // 如果第col列没有用过,并且不在同一对角线上,则选择这一列号 
            if(!used[i] && !dg[u + i] && !udg[u - i]){
                set.push_back(i);
                used[i] = dg[u + i] = udg[u-i] = true;
                dfs(u + 1); // 递归进入下一列
                used[i] = dg[u + i] = udg[u-i] = false;
                set.pop_back();
            }
        }
    }
private:
    int n; // 全局变量 n
    vector<int>set;
    vector<vector<int>> ans;
    unordered_map<int,bool> dg;
    unordered_map<int,bool>udg;
    vector<bool>used;
};

对 ans 内容打印可以得到:

ans:
1 3 0 2
2 0 3 1

可以看到在 \ 对角线上的元素的坐标和都相等, i + j 相等。
在 / 对角线上的元素的坐标差都相等,即 i - j 相等,为了防止出现i - j < 0,而越界的现象, 可以将其开成unordered_map<int,bool>的映射,这样就不用担心越界的问题了。
对于52题求解决方案数量更为容易,只需返回ans.size()即可。

代码示例:
class Solution {
public:
    int totalNQueens(int n) {
        this->n = n;
        used = vector<bool>(n,false);
        dfs(0);
        return ans.size();
    }

    void dfs(int u){ 
        if(u == n){
            ans.push_back(set);
            return;
        }
        for(int col = 0;col < n; col++){
            if(!used[col] && !dg[u - col] && !udg[u + col]){
                set.push_back(col);
                used[col] = dg[u - col] = udg[u + col] = true;
                dfs(u + 1);
                used[col] = dg[u - col] = udg[u + col] = false;
                set.pop_back();
            }
        }
    }
private:
    int n;
    vector<int>set;
    vector<vector<int>> ans;
    vector<bool> used;
    unordered_map<int,bool>dg;
    unordered_map<int,bool>udg;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值