算法040(必备)——N皇后问题

N 皇后 II

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

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

思路:

全排列,验证在各个行放置不同列的可行性

递归函数:返回从i行往后的有效解决方案的数量。

如何判断某位置有效

  • 利用容器接收之前已放入的全部位置,根据规则:不能同列(y!=vec[i]);不能在同一斜对角线(abs(x-i)==abs(y-x_y[i]));不能同行(遍历时自己控制)

大体流程:

basecase:

  • i==N(所有行都已放置过棋子),返回1

recur:

  • 遍历第i行的所有列,若位置有效,则进入下一行并将已填入的pos放入容器中

代码:

class Solution {
public:
    int N;
    bool is_valid(int x, int y, vector<int>& x_y) {
        for (int i = 0; i < x; ++i) {
            if (x_y[i] == y || abs(x - i) == abs(y - x_y[i]))
                return false;
        }
        return true;
    }
    int f(int i, vector<int>& x_y) {
        if (i == N)
            return 1;
        int cnt = 0;
        for (int k = 0; k < N; ++k) {
            if (is_valid(i, k, x_y)) {
                x_y[i] = k;
                cnt += f(i + 1, x_y);
                //x_y[i] = 0;//为什么不需要?判断i和k有效与[i]无关,若有效,后续会覆盖掉
            }
        }
        return cnt;
    }

    int totalNQueens(int n) {
        N = n;
        vector<int> x_y(n);
        return f(0, x_y);
    }
};

优化思路:

优化判断有效的过程(多变量):

  • limit:最终的结果,全部列都被占据(利用二进制的形式,对于占据的列用1表示)
  • col:记录已经占据过的列(二进制形式)
  • left:记录因为‘/对角线’对该行造成的限制
  • right:记录因为‘\对角线’对该行造成的限制
  • 无效ban:无效的全部列;col | left | right
  • 有效valid:有效的全部列;limit&(~ban)

优化遍历的次数,提取所有的有效pos:

  • pos:该行可行的列 valid&(~valid+1)
  • valid的更新:valid^pos

大体流程与思路1一致

优化代码:

class Solution {
public:
    int limit;
    int f(int col, int left, int right) {
        if (col == limit)
            return 1;
        int cnt = 0;
        int ban = col | left | right;
        int valid = limit & ~ban;
        int pos;
        while (valid) {
            pos = valid & (~valid + 1);
            valid ^= pos;
            cnt += f(col | pos, (left | pos) >> 1, (right | pos) << 1);
        }
        return cnt;
    }

    int totalNQueens(int n) {
        limit = (1 << n) - 1;
        int row = 0, col = 0;
        return f(0, 0, 0);
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值