N皇后问题(golang版)

311 阅读2分钟

N皇后问题(golang版)

问题描述

在N*N的棋盘上要摆N个皇后,要求任何两个皇后不同行、不同列,也不在同一斜线上。

给定一个整数n,返回n皇后的摆法有多少种。

n=1,返回1.

n=2或3,2皇后和3皇后问题无论怎么摆都不行,返回0

n=8,返回92

位运算解法:

现在有个8*8的棋盘

我们把可以放的位置用1标记,第一行所有的位置都可以放,所有第一行是1 1 1 1 1 1 1 1

我们一开始在0,Q的位置放一个皇后

image.png 那么第二行的哪些位置可以放皇后呢?

第一行的左斜线是1,0 垂直线是 1,1 右斜线是1,2,这三种位置都不能放

左斜线是:1 0 0 0 0 0 0 0 (第一行放Q的位置左移一位)

垂直线是:0 1 0 0 0 0 0 0 (第一行放Q的位置)

右斜线是:0 0 1 0 0 0 0 0 (第一行放Q的位置右移一位)

三者进行或运算得到

1 1 1 0 0 0 0 0

取反再跟1 1 1 1 1 1 1 1进行与运算得到

0 0 0 1 1 1 1 1

这些为1的位置就可以放皇后

我们假设放到1,4的位置

image.png

第三行哪些位置可以放皇后呢?

左斜线是:0 0 0 1 0 0 0 0 (之前的左斜线左移一位 加上第二行放Q的位置左移一位)

垂直线是:0 1 0 0 1 0 0 0 (之前的垂直线 加上第二行放Q的位置)

右斜线是:0 0 0 1 0 1 0 0 (之前的右斜线右移一位 加上第二行放Q的位置右移一位)

三者进行或运算得到

0 1 0 1 1 1 0 0

取反再跟1 1 1 1 1 1 1 1进行与运算得到

1 0 1 0 0 0 1 1

image.png

第四行在为1的位置放置皇后

周而复始,如果能得到垂直线都填满了,就算是成功得到一种解法

也就是垂直线==1 1 1 1 1 1 1 1

package main
​
import (
   "fmt"
   "math"
)
​
func num1(n int) int {
   if n < 1 {
      return 0
   }
   record := make([]int, n)
   return process1(0, record, n)
}
​
func process1(i int, record []int, n int) int {
   if i == n {
      return 1
   }
   res := 0
   for j := 0; j < n; j++ {
      if isValid(record, i, j) {
         record[i] = j
         res += process1(i+1, record, n)
      }
   }
   return res
}
​
func isValid(record []int, i, j int) bool {
   for k := 0; k < i; k++ {
      if j == record[k] || math.Abs(float64(record[k]-j)) == math.Abs(float64(i-k)) {
         return false
      }
   }
   return true
}
​
func main() {
   fmt.Println(num1(8))
​
   fmt.Println(num2(8))
}
​
func num2(n int) int {
   if n < 1 || n > 32 {
      return 0
   }
   limit := (1 << n) - 1
   return process2(limit, 0, 0, 0)
}
​
func process2(limit, collim, left, right int) int {
   if collim == limit {
      return 1
   }
   mostRight := 0
​
   //得到能放皇后的位置 (用1标识)
   pos := limit & (^(collim | left | right))
​
   res := 0
​
   for pos != 0 {
      mostRight = pos & (^pos + 1) //拿到最右边的1
​
      pos = pos - mostRight //能放的位置--
​
      res += process2(limit, collim|mostRight, (left|mostRight)<<1, (right|mostRight)>>1)
   }
   return res
​
}