八皇后问题python_算法-递归解决八皇后问题-python3实现

0.ժҪ

本文介绍八皇后问题的解决思路,并使用python3实现。

1.问题阐述

目标: 8×8 的国际象棋棋盘上放置八个皇后

规则:任两个皇后都不能处于同一条横行、纵行或斜线上

显然可得: 由于任意皇后不能同行,所以每一行最多放置一位皇后;

由于行数=皇后数,所以每一行至少放置一位皇后

故:正确的放置方式,一定是每行一位皇后(1)

为了方便读者了解规则,我们以4皇后问题为例,简述该类问题的规则与解法。并且,本文以图示的方式进行说明,当一个皇后确定位置后,她的同行、同列、同斜线方向不可以再放置其他皇后。我们用灰色表示不能放置皇后的位置。

step1:放置第一位皇后:现将第一为皇后放在第一列,那么其同一条横行、纵行或斜线位置将不能再放置其她皇后;

step2:放置第二位皇后:第二位皇后只可以放置在第三列或第四列,先尝试放置在第三列;

step3:放置第三位皇后:由于第三行所有位置都无法放置第三位皇后,这与上文(1)出给出的结论相悖,故该放置方式不合理。

重复上述分析过程,可知,无法正确放置第四位皇后,故该方法亦不可行;

继续改变Q1的位置,我们得到了第二种解法。

这时候,我们仔细观察一下,发现第一种和第二种解法是完全对称的!

继续思考一下易得,N皇后问题,当N=偶数时,其解法个数必将是偶数。

2.解题思路

通过上一节对四皇后问题的手动推演,我们可以提取出基本的结题思路: 每一行必定有一位皇后,所以我们只要确定每一行的皇后所处列数即可。

确定一位皇后,我们就需要将其同行、同列、同斜线方向位置标记为不可用

利用遍历+递归的思想,即可实现所有结果的求解

但是,在写code之前,我们还有一个问题需要解决:

那就是同斜线方向的位置,如何判定?

简单的方式,仍然是遍历,判断y1-y2 == x1-x2是否成立即可。但如果每个位置都要先遍历一遍位置阵列,这样的方法计算量太大。是否有更加简单的方法呢?请读者看下面两端代码: def left_diagonal(n): arr = [[0 for _ in range(n)] for _ in range(n)] for i in range(n): for j in range(n): arr[i][j] = i + j return arr if __name__ == '__main__': arr = left_diagonal(8) for a in arr: print(a)

可见,每一个位置的行列值相加,同一左斜线上的和都相等。

这就表明,我们如果想要判定两个元素是否在同一条左斜线上,将其行列值相加,观察和是否相等即可。

在看另外一个程序: def left_diagonal(n): arr = [[0 for _ in range(n)] for _ in range(n)] for i in range(n): for j in range(n): arr[i][j] = i + j return arr def right_diagonal(n): arr = [[0 for _ in range(n)] for _ in range(n)] for i in range(n): for j in range(n): arr[i][j] = i - j + (n - 1) return arr if __name__ == '__main__': arr = right_diagonal(8) for a in arr: print(a)

运行结果:

可见,每一个位置的行列值的差,同一右斜线上的和都相等。

这就表明,我们如果想要判定两个元素是否在同一条右斜线上,将其行列值相减,观察和是否相等即可。

3.使用递归解决八皇后问题:

先看代码 #coding=utf-8 num = 8 result = [-1 for _ in range(num)] enable0 = [True for _ in range(num)] enable1 = [True for _ in range(2*num-1)] enable2 = [True for _ in range(2*num-1)] result = [-1 for _ in range(num)] out_list = [] def queen(r): if (r == 8): # print(result) out_list.append(result.copy()) return 0 else: for c in range(num): if (enable0[c] and enable1[r+c] and enable2[r-c+num-1]): enable0[c] = False enable1[r+c] = False enable2[r-c+num-1] = False result[r] = c queen(r+1) result[r] = -1 enable0[c] = True enable1[r + c] = True enable2[r - c + num-1] = True queen(0) print('Number of all solution :',len(out_list)) one_solution = out_list[1] for index in one_solution: temp = ['_' for _ in range(8)] temp[index] = '*' print(temp)

本代码,通过设置三个辅助数组,enable0,enable1,enalbe2分别表示8列、15条左斜线,15条右斜线的位置可用状态。

通过递归,可以实现所有情况的遍历。

结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值