共本文介绍如何用深度搜索的方式求解8皇后(其实也可以求解N皇后)问题的解
八皇后问题描述
在国际想起的规则中,皇后能攻击八个方向上的棋子,而且不受距离限制。
皇后的攻击方向如下图所示:
八皇后问题则是在这样的规则上,求在一个8*8的棋盘上,如何放置8个互相不会攻击的皇后。
比如下图这样放置:
8个皇后,每个都不在其他皇后的上下左右以及斜向的方向上,所以互相不能攻击。
ps:我写的这份代码其实也可以求N皇后问题的解,只需修改MAXNUM为指定N值即可
代码原理
从棋盘的第一行开始,从左到右的查看每一列,当检测到当前点可以放置皇后,则将该点置为1。
然后查找下一行可以放置皇后的点,寻找的方式也是从左到右的每一列检查,找到后继续找下下一行,直到最后一行,打印此时的棋盘,这代表一个解。
然后回到第一行,遍历下一列,重复上面的过程,直到第一行的每一列都遍历完成。
很明显,这是一次深度搜索的过程,每次找到最后一行的皇后放置位置,就代表找到一个解,把当前的棋盘打印出来即可。
ps:每次查找完当前位置后,记得要将当前位置重新置为0,以供接下来的循环继续寻找其他解
源码
ANSWER_COUNT = 0
MAXNUM = 8
# 检查当前坐标是否能放置queen
# 只需检查当前坐标的↖↑↗这三个坐标上侧方向
# 因为本行的落子不受下一行的影响
# 所以无需检查←↙↓↘→这5个与坐标同行或坐标下侧的方向
def check(x,y,chess):
for i in range(x):
# 检查竖向↑(只需检查当前行之上的行)
if(chess[i][y]==1):
return False
# 检查左上斜方向↖
if(y-1-i >= 0):
if(chess[x-1-i][y-1-i] == 1):
return False
# 检查右上斜方向↗
if(y+1+i < MAXNUM):
if(chess[x-1-i][y+1+i] == 1):
return False
return True
# 打印棋盘
def print_chess(chess):
print('answer {}:'.format(ANSWER_COUNT))
for i in range(MAXNUM):
for j in range(MAXNUM):
print(chess[i][j],' ',end='')
print('\n')
print('\n')
# 递归求解8个queen的放置方式
def find_queen8(x,chess):
global ANSWER_COUNT,MAXNUM
# 临时棋盘,复制上一行的queen皇后落子后的棋盘
chess_temp = [[0 for col in range(MAXNUM)] for row in range(MAXNUM)]
for i in range(MAXNUM):
for j in range(MAXNUM):
chess_temp[i][j] = chess[i][j]
# x等于棋盘边界,代表已最后一行的queen已经落子,打印结果并返回
if(x == MAXNUM):
ANSWER_COUNT = ANSWER_COUNT + 1
print_chess(chess_temp)
return
# 遍历当前行的每一列
for i in range(MAXNUM):
# 判断当前点能否放置queen
if(check(x,i,chess_temp)):
# 能放置,置为1,以供打印棋盘
chess_temp[x][i] = 1
# 寻找下一行queen的落点
find_queen8(x+1,chess_temp)
# 本列的深度搜索结束
# 将本列的点置为0,然后遍历下一列
chess_temp[x][i] = 0
def main():
#初始棋盘
chess = [[0 for col in range(MAXNUM)] for row in range(MAXNUM)]
#从第0行开始
find_queen8(0,chess)
#打印结果
print('求解{}皇后问题,共有{}个答案: '.format(MAXNUM, ANSWER_COUNT))
if __name__ == '__main__':
main()
运行结果
求解八皇后,共92个答案(这是不考虑棋盘的对称性的答案数目,如果考虑棋盘的对称性,甚至棋盘的中轴对称的话,数目会少很多):
求解四皇后,共2个答案(这两个答案其实就是对称的):