Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
解题方法-----
1.回溯法
要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行、同一列、同一对角线。
可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇后放置在第i行的哪一列,所以在放置第i个皇后的时候,可以从第1列判断起,如果可以放置在第1个位置,则跳到下一行放置下一个皇后。如果不能,则跳到下一列...直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。当第n个皇后放置成功后,即得到一个可行解,此时再回到上一个皇后重新放置寻找下一个可行解...如此后,即可找出一个n皇后问题的所有可行解。
class Solution { public: int sum; int *board; int totalNQueens(int n) { sum = 0; board = new int[n+1]; totalN(n,1); delete []board; return sum; } private: void totalN(int n,int k){//放置第k个皇后 if(k>n) sum++; else{ for(int i=1;i<=n;i++){ board[k]=i; if(isok(k)) totalN(n,k+1); } } } bool isok(int k){//check whether the ktn Queen can be put down for(int i=1;i<k;i++){ if(board[i]==board[k]||abs(i-k)==abs(board[i]-board[k])) return false; } return true; } };
2.BIT
补充知识:1)正整数的补码与原码相同;
2)求负整数的补码:原码 符号位不变,数值位各位取反,最后整个数加1得到补码;
3)按位与&的结果是补码与补码运算得到的结果。
class Solution { public: int totalNQueens(int n) { ans = 0; limit = (1<<n) - 1; //左移右边补0 dfs(0, 0, 0); return ans; } void dfs(int h, int r, int l) {//h中1表示与上一行或上多行中的皇后垂直的位置,r表示反斜位置,l表示斜角位置。都是不能放皇后的位置。 if (h == limit) {//此句表示h的每一位都是1,表示上面每行都选好了皇后列的位置,所以ans++ ans++; return; } int pos = limit & (~(h|r|l));//pos是1的位表示此位可以放皇后(刚开始全1表示此行所有位置都可以放皇后) while (pos) { int p = pos & (-pos);//p的二进制表示中是1的位,表示pos中最右边的可放皇后的位置 pos -= p;//pos是1表示此位可以放皇后,此句表示pos中除最右边位其余可以放皇后的位置 dfs(h+p, (r+p)<<1, (l+p)>>1); } } int ans, limit; };