N皇后问题解法

//
// Created by Administrator on 2021/8/5.
//

#ifndef C__TEST01_NQUEENS_HPP
#define C__TEST01_NQUEENS_HPP

#include <iostream>
#include <vector>
#include <unordered_set>
#include <unordered_map>

using namespace std;
class NodeGraph;

/* n皇后问题是指在N*N的棋盘上要摆n个皇后
 * 要求任何两个皇后不同行不同列
 * 给定一个整数n,返回n皇后的摆法有多少种
 * n = 1, 返回1
 * n = 2 or 3, 无论怎么摆都不行,返回0
 * n = 8, 返回92
 * */
class NQueens {
public:
    int num1(int n){
        vector<int> record(n);//第i行的皇后放在第几列
        return process1(0, record, n);
    }

    //目前来到的第i行,一共有n行
    int process1(int i, vector<int> record, int n){
        if(i == n){
            return 1; //表示已经到了最后一行,所以次数加1
        }
        int res = 0;
        for (int j = 0; j < n; ++j) {
            //第i行的皇后放在第j列是不是有效的
            if(isValid(record, i, j)){
                record[i] = j;
                res +=  process1(i+1, record, n);
            }
        }
        return res;
    }
    bool isValid(vector<int> record, int i, int j){
        for(int k = 0; k < i; k++){
            if(j == record[k] || abs(record[k]-j) == abs(i-k)){
                return false;
            }
        }
        return true;
    }

    int num2(int &n){
        if(n < 1 || n > 32){
            return 0;
        }
        int limit = n == 32 ? -1 : (1<<n)-1;
        // -1就是32个1,
        // 其余情况, 比如n是5 就是 100000-1 = (前面凑0)011111
        return process2(limit, 0, 0, 0);
    }

    int process2(int &limit,
                 int colLim,  //列的限制, 1的位置不能放皇后,0的位置可以
                 int leftDiaLim,//左斜线的限制, 1的位置不能放皇后,0的位置可以
                 int rightDiaLim //右斜线的限制, 1的位置不能放皇后,0的位置可以
                 ){
        if(colLim == limit){
            return 1;
        }
        int pos = 0;
        int mostRightOne = 0;
        //三个限制是或的关系,或在一起的1的位置不能放皇后
        //再取反,就是0的位置不能放皇后
        //与 limit 与,就是可以放皇后的位置
        pos = limit & (~(colLim|leftDiaLim|rightDiaLim));
        int res = 0;
        while(pos != 0){
            mostRightOne = pos & (~pos + 1);//取到可摆放位置的最右边的1
            pos = pos - mostRightOne; //剩下的可以拜访的位置
            res += process2(limit,
                            mostRightOne|colLim,
                            (mostRightOne|leftDiaLim) << 1,
                            (mostRightOne|rightDiaLim) >> 1);
        }
        return res;
    }
};


#endif //C__TEST01_NQUEENS_HPP

posted @ 2021-08-10 12:01  蘑菇王国大聪明  阅读(84)  评论(0编辑  收藏  举报