b_lc_N皇后(一列一列地放,放完就检查)

构造n皇后

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

上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

输入:4
输出:[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

思路
回溯放置皇后 'Q' 和棋子 '.',放完整个棋盘后就对于每一种放置方案都检查是否合法,这是最朴素的做法;
剪枝:每放完一列就去检查当前方法是否合法(这里为了方便选择每次放完一列)

const int N=100;
class Solution {
public:
    int n; char g[N][N];
    vector<vector<string>> ans;
    bool chk(int x, int y) {
        for (int i=x-1; i>=0; i--) {
            int d=x-i;
            if (g[i][y]=='Q' || (y-d>=0 && g[i][y-d]=='Q') || (y+d<n && g[i][y+d]=='Q'))
                return false;
        }
        return true;
    }
    void dfs(int i) {
        if (i==n) {
            vector<string> now;
            for (int i=0; i<n; i++) {
                string s;
                for (int j=0; j<n; j++)
                    s+=g[i][j];
                now.push_back(s);
            }
            ans.push_back(now);
            return;
        }
        for (int j=0; j<n; j++) if (chk(i, j)) {
            g[i][j]='Q';
            dfs(i+1);
            g[i][j]='.';
        }
    }
    vector<vector<string>> solveNQueens(int n) {
        this->n=n;
        memset(g,'.',sizeof g);
        dfs(0);
        return ans;
    }
};

复杂度分析

  • Time\(O(2^n)\)
  • Space\(O(...)\)

题外话:

  • 主对角线特点:所有格子格子的行下标与列下标之相同
  • 辅对角线特点:所有格子格子的行下标与列下标之相等

合法的序列

Q1,Q2,…,QN 来表示一种棋盘摆放,其中 Qi 表示第 i 列的皇后所在的行号。

疑惑
不知道为什么用一个map来记录两条对角线为什么不行(加了10w的偏置值也不行)

#include<bits/stdc++.h>
using namespace std;
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int q; cin>>q;
    for (int i=0; i<q; i++) {
        int m,valid=1; 
        cin>>m;
        unordered_map<int, bool> mx, my, md1, md2;
        for (int y=1; y<=m; y++) {
            int x; cin>>x;
            if (mx[x] || my[y] || md1[x+y] || md2[x-y]) {
                valid=0;
            }
            mx[x]=my[y]=md1[x+y]=md2[x-y]=1;
        }
        cout<<(valid ? "YES" : "NO")<<'\n';
    }
    return 0;
}

N皇后II

给定一个棋盘大小n,返回n皇后不同的解决方案的数量。

思路:记录每一行放下的皇后的位置

class Solution:
    ans=0
    def totalNQueens(self, n: int) -> int:
        def valid(x,row):
            for c in range(x):
                if row[c]==row[x] or abs(x-c)==abs(row[x]-row[c]):
                    return False
            return True
        def dfs(x,row):
            if x==n:
                self.ans+=1
                return
            for y in range(n):
                row[x]=y
                if valid(x,row):
                    dfs(x+1,row)
        row=[0]*n
        dfs(0,row)
        return self.ans
posted @ 2020-09-03 11:46  童年の波鞋  阅读(161)  评论(0编辑  收藏  举报