对于八皇后问题,大家应该都不陌生,只要接触过算法的,必然都会接触到这到题。对于八皇后的问题不在此叙述,可以直接百度。对于八皇后问题的解决思路,可以直接根据题目的要求便可以得到。
总的来说,就是下一个皇后放置的点不能在上图所画的实线当中。
这里我仅考虑有多少种放置方法,而不考虑如何去放置。
深度优先搜索
DFS版本的解法应该是最普遍,直接通过回溯便可以解决。
def dfs(queues, xy_sum, xy_dif, num):
global count
row = len(queues)
if row == num: # 所有皇后都放置完成
count += 1
for col in range(num): # 一列一列的尝试放置
if col not in queues and row+col not in xy_sum and row-col not in xy_dif: # 列不冲突,左右斜线都不冲突
dfs(queues+[col], xy_sum+[row+col], xy_dif+[row-col], num) # 下一层的皇后
global count
count = 0
dfs([], [], [], 4)
print(count)
广度优先搜索
广度优先与深度优先作为一对兄弟,竟然能使用深度优先搜索来实现,则必然也可通过广度优先来实现(感谢好兄弟的提醒)
def bfs(num):
global count
queues = [] # 皇后点的队列
# 初始化所有可能的点 也就是第一行中的所有点
for i in range(num):
queues.append(tuple((0, i, [0], [i], [0+i], [0-i]))) # 点x, 点y,行,列,xy_sum, xy_dif
while queues:
row, col, rows, cols, xy_sum, xy_dif = queues.pop(0)
if row == num-1: # 到达最后一行了,将结果加1,直接下一轮
count += 1
continue
row += 1
for col in range(num): # 判断每个位置是否可以存放
if row not in rows and col not in cols and row+col not in xy_sum and row-col not in xy_dif:
queues.append(tuple((row, col, rows+[row], cols+[col], xy_sum+[row+col], xy_dif+[row-col])))
return count
global count
count = 0
bfs(8)
print(count)
位运算
对于八皇后问题的解决,还有一种最不常见的方法,便是位运算,其实位运算的整体思路与DFS相似,只是通过使用位运算来进行判断以提高程序的运行速度。
def bitcom(row, col, xy_sum, xy_dif, num):
global count
if row == num:
count += 1
bits = (~(col|xy_sum|xy_dif)) & ((1<<num)-1) # 得到有效空位 不放在col,xy_sum, xy_dif线上 & 获取后num位可放置的位置
while bits:
p = bits & -bits # 从后往前逐个获取可放置的位置 这边也就是从后朝前获取1的位置
bitcom(row+1, col|p, (xy_sum|p)<<1, (xy_dif|p)>>1, num) # col|p 为去掉刚刚放置的列 (xy_sum|p)<<1 下一行种当前斜线上不能放的位置置0
bits = bits & (bits-1) # 清零最低为的1,即将已放置过的位置置0
global count
count = 0
bitcom(0, 0, 0, 0, 8)
print(count)