这个讲解比较好理解:回溯法与N皇后问题
N皇后问题,题目意思是在N * N的棋盘当中放置N个皇后,这N个皇后要“和平相处”,若任意两个皇后处在同一行,同一列,或者同一对角线上,那么这两个皇后就要打起来。
先直观理解一下这题的解法,从第一行开始放置皇后,在每一行放置的时候都需要检查当前列是否能够可以放皇后,如果可以放置,OK,进入下一行,如果不能够放置,那么进入该行的下一列再进行判断,如果直到该行的末尾都无法放置皇后,那么返回上一行,改变上一行皇后的位置,再重复上述的操作。如果能够走到最后一行放置皇后,这就是一种可行的解法。而当第一行的皇后走到末尾列的时候,就是整个搜索过程的结束。
算法思想好理解,但是把它们翻译成代码,就不是那么好写的了
所需变量:
- column:首先我们需要一个一维数组来记录已放置的皇后的位置,数组元素的下标表示行数,数组元素的值表示列数,将该数组记作column
- row,col:当前位置是处于哪一行,哪一列
- total:记录解法的数量
- n:皇后的个数
步骤:
- 辅助函数isOK(row, col):判断当前位置是否能够放置皇后,遍历已经当前行数之前的皇后,如果有皇后的列数等于当前的列数(同一列),或者行数差的绝对值等于列数差的绝对值(同一对角线),说明会冲突
def isOk(self,row, col):
for i in range(0, row):
if(col == self.column[i] or abs(row - i) == abs(col - self.column[i])):
return False
return True
- 主函数:首先判断当前行是否是最后一行,如果是,解法加1,如果不是,寻找当前行的合适位置,如果合适的话,进入下一行,如果不合适继续寻找。如果该行找不到合适的位置,那么当前循环结束,回退到上一行的queue循环当中
def queue(self, row):
if(row == self.n):
self.total += 1
else:
for col in range(0, self.n):
self.column[row] = col
if(self.isOk(row, col)):
self.queue(row + 1) # 进入下一行
完整代码如下:
class Solution:
def isOk(self,row, col):
for i in range(0, row):
if(col == self.column[i] or abs(row - i) == abs(col - self.column[i])):
return False
return True
def queue(self, row):
if(row == self.n):
self.total += 1
else:
for col in range(0, self.n):
self.column[row] = col
if(self.isOk(row, col)):
self.queue(row + 1)
def totalNQueens(self, n: int) -> int:
self.total = 0
self.n = n
self.column = [0] * self.n
self.queue(0)
return self.total