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) } } }
二、以四皇后(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文件浏览
!--?xml>以上是关于N皇后的位运算解法的主要内容,如果未能解决你的问题,请参考以下文章