N皇后的位运算解法

Posted wwcxblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了N皇后的位运算解法相关的知识,希望对你有一定的参考价值。

一、N皇后二进制Java代码:

技术图片
public class Solution{
  int count = 0;
  public int totalNQueue(n) {
    if (n < 1) {
      return n;
    }
    //int类型只能表示最大值为32*32的棋盘,如果大于32,则要使用long型
    DFS(0,0,0,0,n);
    return count;
  }
  
  /**
   * 使用DFS方法递归获取每一行可以放置皇后的位置
   * row:表示棋盘的行,最大值为n
   * col:表示棋盘的列。col的int值的右n位用来表示棋盘的列,若某一位二进制数为0(不能放置皇后),若为1(可以放置皇后)
   * pie:表示棋盘的左斜列。pie的int值的右n位用来表示棋盘的列,若某一位二进制数为0(不能放置皇后),若为1(可以放置皇后)
   * na:表示棋盘的右斜列。na的int值的右n位用来表示棋盘的列,若某一位二进制数为0(不能放置皇后),若为1(可以放置皇后)
   * n:表示棋盘是n*n的棋盘
   */
  private void DFS(int row, int col, int pie, int na, int n) {
    //当棋盘的行数累加到n时,就表示所有的行都已走完,获取到一种放置皇后的方法,count加1记录
    if(row >= n) 
      count++;
      return;
    }
    // 当前行可以放置皇后的位置(右n位有几个1存在,就表示有几个可以放置皇后的位置。0表示不能放置)
      // (col | pie | na):表示第一行所有的位置都为0(后续根据计算值获取)。使用 ~ 取反后,棋盘所有的位置都为1,
    // 棋盘第一行所有的位置都可以放置皇后
      // (1 >> n) - 1:将1的二进制左移n位,经过减1后,就将32-n位全部置为0,n为全部置为1;
      // 由于只需要后n位就可以表示棋盘的一行,所以进行 & 运算,就可以保证除了右n位,其余位都为0;
    int poss = (~(col | pie | na)) & ((1 << n) - 1);
      // poss不为0,表示poss中存在二进制位为1的,即存在可以放置皇后的位置
    while(poss != 0) {
      //获取二进制位中最右边的1,将皇后放在该位置
      int pos = poss & (-poss);
      //递归每一行,处理皇后第一行在pos位置时,从第2行到第n行的皇后的摆放位置
      //na要进行无符号的右移1位。是因为如果皇后在最高的32位时,会报错
      DFS(row + 1, col | pos, (pie | pos) << 1, (na | pos) >>> 1, n);
      //清除二进制位中最右边的1
      poss = poss & (poss - 1)
    }
  }
}
View Code

二、以四皇后(n=4)为例对代码进行分析(粗体四位表示棋盘当前行的状态)

    (1 << n) - 1:
        a                                                             1:    00000000 00000000 00000000 00000001
                        b                                                     1 << n:    00000000 00000000 00000000 00010000
                c                                                        b - a:   00000000 00000000 00000000 00001111

1、第一轮(0, 0, 0, 0, n):排版像狗屎一样,编辑器真的不会用

1)第一行皇后放置位置计算

    ① d                                                   (col | pie | na):     00000000 00000000 00000000 00000000
 
    ② e                                                                   ~d:     11111111      11111111      11111111     11111111
 
    ③ poss                                                          e & c:     00000000 00000000 00000000 00001111                 ==> 15
 
    ④ -poss                                      (对f取反,然后加1):      11111111     11111111      11111111      11110001
 
    ⑤pos                                              poss & (-poss) :      00000000 00000000 00000000 00000001
 
   //第一行的皇后放在了(0,3)的位置,col(1,3)、(2,3)、(3,3)都不能再放,pie(1,2)、(2,1)、(3,0)都不能再放
1
1
1
皇后
1
1
0
0
1
0
1
0
0
1
1
0
    ⑥进入棋盘第二行递归参数:
      row: row + 1 = 1 + 1 = 2;
      col: 1
        col:     00000000 00000000 00000000 00000000
        或             |
        pos :     00000000 00000000 00000000 00000001
        结果:   00000000 00000000 00000000 00000001
 
      pie: 2
        pie:     00000000 00000000 00000000 00000000
        或             |
        pos :   00000000 00000000 00000000 00000001
        左移1位           << 1
        结果:   00000000 00000000 00000000 00000010
      
      na: 0
        na:    00000000 00000000 00000000 00000000
        或             |
        pos :   00000000 00000000 00000000 00000001
        无符号右移1位                  >>>1
        结果:     00000000 00000000 00000000 00000000

2)第二行皇后位置计算,第一行皇后在(0,3)

          c b - a:                                  00000000 00000000 00000000 00001111
 
      ① d (col | pie | na):                              00000000 00000000 00000000 00000001
                                                                           00000000 00000000 00000000 00000010
                                                                           00000000 00000000 00000000 00000000
                                                             结果:     00000000 00000000 00000000 00000011
 
                  ② e                                          ~d:     11111111 11111111 11111111 11111100
 
                  ③ poss                                 e & c:     00000000 00000000 00000000 00001100                    ==> 12
 
                  ④ -poss             (对f取反,然后加1):     11111111 11111111 11111111 11110100
 
                  ⑤ pos                   poss & (-poss) :     00000000 00000000 00000000 00000100
 
            //第一行的皇后放在了(0,3)的位置,col(0,1)、(3,1)都不能再放,pie(2,0)不能再放,na(2,2) 不能再放
1
0
1
皇后
1
皇后
0
0
0
0
0
0
0
0
1
0
                 ⑥进入棋盘第三行递归参数:
                                   row: row + 1 = 2 + 1 = 3;
                                   col: 5
                                         col:     00000000 00000000 00000000 00000001
                                          或                                 |
                                         pos :   00000000 00000000 00000000 00000100
                                         结果: 00000000 00000000 00000000 00000101
 
                                   pie: 4
                                           pie:   00000000 00000000 00000000 00000010
                                           或                                 |
                                         pos :   00000000 00000000 00000000 00000100
                                        左移1位                          << 1
                                         结果: 00000000 00000000 00000000 00001100
 
                                    na: 2
                                           na:    00000000 00000000 00000000 00000000
                                           或                                 |
                                        pos :    00000000 00000000 00000000 00000100
                                       无符号右移1位                   >>>1
                                        结果:  00000000 00000000 00000000 00000010

3)第三行皇后位置计算,第二层皇后在(1,1)

                   c                                 b - a:     00000000 00000000 00000000 00001111
 
      ① d                  (col | pie | na):     00000000 00000000 00000000 00000101
                          00000000 00000000 00000000 00001100
                                                                  00000000 00000000 00000000 00000010
                                                    结果:     00000000 00000000 00000000 00001111
 
                  ② e                                 ~d:     11111111 11111111 11111111 11110000
 
      ③ poss                        e & c:     00000000 00000000 00000000 00000000                        ==> 0 poss=0 ,不进入此while循环
 
                  //走完第三层的逻辑,递归返回第二层,进行 poss = poss & (poss - 1) 操作,此时的poss为第二层的: 00000000 00000000 00000000 00001100 ==> 12
 
                  ④ e                        poss - 1 :     00000000 00000000 00000000 00001011                ==> 12 - 1 = 11;
 
                  ⑤ 更新后的poss      poss & e :     00000000 00000000 00000000 00001000               ==> 8
 
                   //poss更新,由于poss=8,不等于0;所以进入下一个while循环
 
                  ⑥ -poss    (对f取反,然后加1):     11111111 11111111 11111111 11111000
 
                  ⑦ pos          poss & (-poss) :      00000000 00000000 00000000 00001000               ==> 8
                 
                 //根据pos的后四位1000,皇后的位置如下图所示:
0
0
1
皇后
皇后
0
0
0
0
0
1
0
0
0
0
0
 
                   然后进入第二行皇后在(1,0)位置的下一层DFS梦境(第三行),去寻找第三行的皇后的可以放置的位置
         
                  ⑧进入棋盘第三行递归参数,如下:
                                row: row + 1 = 2 + 1 = 3;
 
                                 col: 9
                                       col:        00000000 00000000 00000000 00000001
                                        或                                       |
                                     pos :        00000000 00000000 00000000 00001000
                                     结果:      00000000 00000000 00000000 00001001
 
                                pie: 20
                                       pie:        00000000 00000000 00000000 00000010
                                       或                                         |
                                       pos :      00000000 00000000 00000000 00001000
                                       左移1位                             << 1
                                       结果:    00000000 00000000 00000000 00010100
 
                                 na: 4
                                       na:         00000000 00000000 00000000 00000000
                                       或                                       |
                                       pos :      00000000 00000000 00000000 00001000
                                       无符号右移1位                    >>>1
                                       结果:    00000000 00000000 00000000 00000100

4)再次进行第三行皇后位置计算(第二层皇后在1,0位置)

             c                           b - a:                00000000 00000000 00000000 00001111
 
    ① d             (col | pie | na):                00000000 00000000 00000000 00001001
                                      00000000 00000000 00000000 00010100
                                      00000000 00000000 00000000 00000100
                       结果:              00000000 00000000 00000000 00011101
 
            ② e                             ~d:                 11111111 11111111 11111111 11100010
    ③ poss                    e & c:                 00000000 00000000 00000000 00000010 ==> 1
    ④ -poss (对f取反,然后加1):                 11111111 11111111 11111111 11111110
    ⑤ pos        poss & (-poss) :                00000000 00000000 00000000 00000010
 
    //根据pos的后四位0010,皇后的位置如下图所示,col(0,2)不能在放置,同一列。pie(3,1)不能放置皇后:
0
0
0
皇后
皇后
0
0
0
0
0
皇后
0
0
0
0
0
 
     然后进入第三行皇后在(2,2)位置的下一层DFS梦境(第四行),去寻找第四行的皇后的可以放置的位置:
 
    ⑥进入棋盘第三行递归参数,如下:
        row: row + 1 = 3 + 1 = 4;
 
        col: 13
          col:   00000000 00000000 00000000 00001001
          或             |
          pos :    00000000 00000000 00000000 00000010
          结果:    00000000 00000000 00000000 00001011
 
        pie: 44
          pie:     00000000 00000000 00000000 00010100
           或            |
          pos :       00000000 00000000 00000000 00000010
          左移1位                           << 1
          结果:     00000000 00000000 00000000 00101100
 
        na: 3
          na:          00000000 00000000 00000000 00000100
          或                                   |
          pos :        00000000 00000000 00000000 00000010
          无符号右移1位                >>>1
              结果:       00000000 00000000 00000000 00000011

4)进行第四行皇后位置计算(第三层皇后在2,2位置)

    c                      b - a:                   00000000 00000000 00000000 00001111
 
    ① d       (col | pie | na):                  00000000 00000000 00000000 00001011
                                                               00000000 00000000 00000000 00101100
                                                               00000000 00000000 00000000 00000011
                                      结果:                00000000 00000000 00000000 00101111
 
            ② e                       ~d:                   11111111 11111111 11111111 11010000
    
    ③ poss              e & c:                    00000000 00000000 00000000 00000000                 ==> 0                     不进入此while循环,第四层没有位置可以放置皇后
0
1
0
皇后
皇后
0
0
0
0
0
皇后
0
0
0
0
0
 
  Ps:
    1)由于第四行没有放置皇后的位置,返回到第三层梦境,更换第三层皇后的位置;
    2)由于第三层没有其它可以放置皇后的位置(如上图所示),再返回第二层梦境,更换第二层皇后的位置;
    3)由于第二层也没有其它可以放置皇后的位置(如上图所示),再返回第一层梦境,更换第一层梦境皇后的位置,按照上述逻辑进行分析,直到找到可 以以放置每一层皇后位置的方法,然后返回;
 
我将.md文件放在了百度云盘,想看好的排盘的请自行下载:链接:  https://pan.baidu.com/s/19rdTce10winD0lLwtTZhgQ  密码:adim  
请使用Typora或者其他的.md文件浏览

以上是关于N皇后的位运算解法的主要内容,如果未能解决你的问题,请参考以下文章

n皇后(位运算)

n皇后问题 非递归解法1

八皇后究竟有多少种解法?怎么解?

八皇后问题的遗传算法解法,c语言编写

hdu 2553 n皇后问题DFS递归解法

leetcode| 51. N皇后问题