【基于位运算的回溯法】N皇后问题2

原题目链接:https://leetcode-cn.com/problems/n-queens-ii/
这个题目与leetcode 51 题唯一不同在于输出不同,本题只要求输出几种解法
51题要求输出每种解的具体形式
上篇文章用回溯法和基于集合的回溯法解决 51 题,这次使用位运算来解决
为了更好理解代码后注释的1,2,3 表示步骤,下面会模拟程序执行过程逐步进行解释。

class Solution:
    def solveNQueens(self, n: int):
        def dfs(row, col, pie, na):
        	"position  中 1 表示可以放皇后的位置"
        	"p 中 1 表示放皇后的位置"
        	"col,pie,na, 中 1 表示受上一行皇后影响该行不能放皇后的位置"
        	"pie,na 不符命名规则,但是方便理解 撇,捺"
        	"pie 右上角到左下角,na 左上角到右下角"
            if row == n:  # 1
                return 1
            res = 0  # 2
            position = (~(col | pie | na)) & ((1 << n) - 1)  # 3
            while position:  # 4
                p = position & (-position)  # 5
                position &= position - 1  # 6
                res += dfs(row + 1, col | p, (pie | p) << 1, (na | p) >> 1)  # 7
            return res
        return dfs(0, 0, 0, 0)

"""
 与   &  逢 0 为 0
 或   |  逢 1 为 1
取反  ~  1 变 0, 0 变 1
左移  <<   
右移  >>
以 4 为例 4 的二进制  0100 
         1 的二进制  0001
 4 & 1 -> 0100 & 0001 = 0000
 4 | 1 -> 0100 | 0001 = 0101
   ~4  ->       ~0100 = 1011
4 << 1 ->   0100 << 1 = 1000
4 >> 1 ->   0100 >> 1 = 0010


以 n=4为例:
dfs(0,0,0,0)从步骤1开始
1. 行数不等于n,不进入
2. res=0
3. position = (~( 0 | 0 | 0 )) & (( 1 << n )-1)
            (~0) & (1 0000 - 0000 1) -> 1111 & 1111 -> 1111
   position = 1111  含义:在第一行的四个位置上都可以放皇后
    |√|√|√|√|
	|-|-|-|-|
	|-|-|-|-|
	|-|-|-|-|
   

4. position 不为0 进入循环                                
5. p =  1111 & 0001
   p = 0001  含义:此时在第一行最后一个位置上放置皇后
    |-|-|-|Q|
	|-|-|-|-|
	|-|-|-|-|
	|-|-|-|-|
6. position &= position - 1
        1111 & (1111 - 0001) -> 1111 & 1110
    position = 1110  含义:第一行还有前三个位置可以放置皇后
    |√|√|√|Q|
	|-|-|-|-|
	|-|-|-|-|
	|-|-|-|-|

7. 进入第二层 dfs(1, 0001, 0010, 0000)
            这里 col pie na 就详细计算一次,下文不再详细展示
            col | p = 0000 & 0001 = 0001
            (pie | p) = (0000 & 0001) <<1 = 0001 << 1 = 0010
            (na | p) = (0000 & 0001) >> 1 = 0001 >> 1 = 0000
            dfs(第二行,最后一个位置,第三个位置, 第五个位置(超出所以是0))  
1. 行数不等于n,不进入
2. res = 0
3. position = (~(0001 | 0010 | 0000)) & (( 1 << n)-1) 
        通过 | 将第二行不能放皇后的情况重合到一起  0011代表第二行后两个位置都不能放置皇后
        		|-|-|×|×|
              (~0011) & (1111) -> 1100 & 1111 
   position = 1100 含义:第二行前两个位置可以放置皇后
    |√|√|√|Q|
	|√|√|×|×|
	|-|-|-|-|
	|-|-|-|-|

4. position 不为零 进入循环
5. p = 1100 & 1011
    p = 1000 含义:第二行第一个位置放皇后
    |√|√|√|Q|
	|Q|√|×|×|
	|-|-|-|-|
	|-|-|-|-|
6. position &= position - 1
       1100 & 1011 -> 0100 
    position = 0100 含义:第二行第二个位置可以放置皇后
    
    
7. 进入第三层 dfs(2, 1001, 0100, 0100)
1.不进入
3. position = (~(1001 | 0100 | 0100)) & ((1 << n)-1)
        通过 | 将第三行不能放皇后的情况重合到一起  1101代表第三行行只有第三个位置可以放
        										|×|x|√|x|
            (~1101) & (1111) -> 0010 & 1111 
    position = 0010 含义:只有第三个位置可以放
    |√|√|√|Q|
	|Q|√|×|×|
	|×|x|√|x|
	|-|-|-|-|
5. p = 0010 & 1110
   p = 0010 含义:第三行第三个位置放置皇后
   	|√|√|√|Q|
	|Q|√|×|×|
	|×|x|Q|x|
	|-|-|-|-|
6. position &= position - 1 
    0010 & (0010 -1 ) -> 0010 & 0001
    position = 0000 含义:第三行已经没有位置可以放置皇后了
    
    
7. 进入第四层 dfs(3, 1011, 1100, 0011)
3. position = (~(1011 | 1100 | 0011)) & ((1 << n)-1)
            此时已经可以看出 第四行已经没有合适位置放置皇后了
            因为,col | pie | na = 1111  |×|x|x|x|
            (~1111) & (1111) 
    position = 0000 含义:没有位置可以放置皇后了
    |√|√|√|Q|
	|Q|√|×|×|
	|×|x|Q|x|
	|×|x|x|x|
4. position = 0 不进入循环 此时开始退出递归 返回到第三行
    但是第三行中position = 0000 表明也没有可以放置的地方
    (或者说只有一个地方可以放,已经放过了),继续返回到第二层
    此时第二层的position = 0100 表示第二层还有一个地方可以放皇后,
    返回到第二层将原来的Q放在第二个位置上
	|√|√|√|Q|          |√|√|√|Q|
	|Q|√|×|×|          |x|Q|×|×|
	|-|-|-|-|          |-|-|-|-|
	|-|-|-|-|		   |-|-|-|-|
 第二层原来的方法     回溯到第二次重新放
	
	然后继续循环                      
"""
s = Solution()
print('n = 4 时有', s.solveNQueens(4), '种解')
print('n = 5 时有', s.solveNQueens(5), '种解')
print('n = 8 时有', s.solveNQueens(8), '种解')

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值