zoukankan      html  css  js  c++  java
  • 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):

    排版像狗屎一样,编辑器真的不好用,

    我将.md文件放在了百度云盘,想看好的排盘的请自行下载:链接:  https://pan.baidu.com/s/19rdTce10winD0lLwtTZhgQ  密码:adim  
    请使用Typora或者其他的.md文件浏览

    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)由于第二层也没有其它可以放置皇后的位置(如上图所示),再返回第一层梦境,更换第一层梦境皇后的位置,按照上述逻辑进行分析,直到找到可 以以放置每一层皇后位置的方法,然后返回;
     
     
  • 相关阅读:
    【大数据】HDFS高可用
    【Redis】常用命令、问题排查、内存优化
    【OOM】记一次线上OOM解决全流程
    【Git】Github如何弥补提交记录contributions
    Hash算法与Hash碰撞
    【计算机基础】存储单位换算
    【大数据】技术选型对比
    【MQ】Kafka架构与原理
    【Git】Git常用命令合集
    【maven】基本知识点
  • 原文地址:https://www.cnblogs.com/wwcxBlog/p/13405392.html
Copyright © 2011-2022 走看看