今天突然有个行外的朋友扔了一张图给我,希望我能帮他用python做一下这个作业——八皇后问题。
八皇后问题是一种经典的数学求解问题,规则是在8×8的国际象棋棋盘上,要求在每一行(或者每一列)放置一个皇后,且能做到在水平方向、竖直方向和斜方向都没有冲突。
关于这个问题的编程实现,首先我们将棋盘等价于一个8×8的矩阵(二维数组),矩阵中的点(x,y)指代棋盘第x行y列的位置。而冲突的自然语言定义是同行、同列或同对角线,那么这个逻辑换算到程序中,我们可以认为两点(x1,y1)和(x2,y2)至少满足以下四个条件之一:
一开始看到这个问题的规则,我有些小瞧了它的难度,以为通过逐行排除过滤就可以推出可行解,因此稍微整理一下思路就草草开干了,最后毫无疑问地踩了不少坑。在这个问题上,逐行定点的方式是可行的,关键在于八皇后问题在这种求解方式下存在死解,即可能在中途某行进行取点时,发现该行上没有一个点符合要求。因此,八皇后问题的程序求解归根到底其实是一个回溯遍历的问题。通过回溯,我重新调整了思路:
1、从第一行开始,按照冲突规则过滤出每行目前可选的位置点集合,取一点;
2、如果遇到死解,即当前行没有符合要求的可选点,则回退到上一行,重新取点;
3、直到第八行取到了符合要求的安全位置,求解成功。
捋清了这个编程思路,利用python实现也就不难了。
# 指定行过滤出可选位置并随机选取一个,作为本行queen的填入位置 # 在后续过程中保存本行过滤完的可选位置 # 这个变量标志了该位置是否可用,初始化的时候是False,可用 # 只要有一个出现同列或同对角线,或位于排除项列表中时,将available标记为不可用 # 该位置可用,添加进可用项数组里 # 死解,返回0,指示不成功 # 活解,随机挑选位置点,返回1,指示成功 # 根据最终结果用图表展示出来 # 没有遇到死解,继续往下 # 遇到了死解,回退到上一行并且将死解的点存入排除项中,重新选点 # 由于是自上而下选点的方式,当上一行的点重新选取时,后一行的排除项已经没有意义了,清空