N-Queens II
Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
1 class Solution 2 { 3 private: 4 // 试探算法从最右边的列开始。 5 void test(long row, long ld, long rd) 6 { 7 if (row != upperlim) 8 { 9 // row,ld,rd进行“或”运算,求得所有可以放置皇后的列,对应位为0, 10 // 然后再取反后“与”上全1的数,来求得当前所有可以放置皇后的位置,对应列改为1。 11 // 也就是求取当前哪些列可以放置皇后。 12 long pos = upperlim & ~(row | ld | rd); 13 while (pos) // 0 -- 皇后没有地方可放,回溯。 14 { 15 // 拷贝pos最右边为1的bit,其余bit置0。 16 // 也就是取得可以放皇后的最右边的列。 17 long p = pos & -pos; 18 19 // 将pos最右边为1的bit清零。 20 // 也就是为获取下一次的最右可用列使用做准备, 21 // 程序将来会回溯到这个位置继续试探。 22 pos -= p; 23 24 // row + p,将当前列置1,表示记录这次皇后放置的列。 25 // (ld + p) << 1,标记当前皇后左边相邻的列不允许下一个皇后放置。 26 // (ld + p) >> 1,标记当前皇后右边相邻的列不允许下一个皇后放置。 27 // 此处的移位操作实际上是记录对角线上的限制,只是因为问题都化归 28 // 到一行网格上来解决,所以表示为列的限制就可以了。显然,随着移位 29 // 在每次选择列之前进行,原来N×N网格中某个已放置的皇后针对其对角线 30 // 上产生的限制都被记录下来了。 31 test(row | p, (ld | p) << 1, (rd | p) >> 1); 32 } 33 } 34 else 35 { 36 // row的所有位都为1,即找到了一个成功的布局,回溯。 37 sum++; 38 } 39 } 40 41 public: 42 int totalNQueens(int n) 43 { 44 upperlim = 1; 45 sum = 0; 46 47 upperlim = (upperlim << n) - 1; 48 test(0, 0, 0); 49 50 return sum; 51 } 52 private: 53 int upperlim; 54 int sum; 55 };