共本文介绍如何用深度搜索的方式求解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个答案(这两个答案其实就是对称的):

发表评论

电子邮件地址不会被公开。 必填项已用*标注