《programming for the puzzled》第四章
涉及到的问题:二维列表,while循环,continue语句,函数的默认参数,用递归进行搜索,剪枝(Conflict detection)。
就是所谓的“八皇后问题”了,在一个8×8的国际象棋棋盘上放8个皇后,要求它们不能彼此攻击,即:
①没有两个皇后在同一行。
②没有两个皇后在同一列。
③没有两个皇后在同一对角线上。
先考虑小规模的问题,5×5的棋盘上放5个皇后。
我先自己尝试一下,用穷举吧。
1 | # 穷举法 |
还是照网上的抄的,用一维列表表示棋盘上每行放皇后的那列的位置。
再来看书里的解法,用的是二维列表表示棋盘。
关键是判断一个放法是否符合问题的三个要求。
1 | # 工具函数,检查棋子布局是否合规 |
qindex是已经放了棋子的行的位置,相应的列的位置是current。
我自己照着书敲,老是出错,结果不对。把书的代码复制粘贴过来运行才发现是棋盘初始化出错了。
1 | # 工具函数 输出二维棋盘 |
2维数组代表棋盘是一个很自然的想法,但由于我们在每一列仅放一个皇后(每一行也是一样的),我们可以用一维数组代表某一列放皇后的位置,而其取值代表了在该列所放皇后的行数。
每个元素的取值范围为[-1,3],-1意味着这一列没有放棋子,0代表放在该列的第一行,3代表放在该列的最后一行。
1 | # 判断布局是否违反规则 |
现在来做八皇后问题。
1 | # 八皇后 回溯 |
跟前面穷举法相比,一旦遇到有冲突的落子方案,直接就pass了,快很多。
每次落子,都要调用监测是否有冲突的判断函数。
这是全书中“最丑”的代码了。可以改进的。用递归代码,在问题10的时候。
算法的核心思想是遍历所有可能的下棋方法,不遗漏任何一个可能。
另一种方法是在将布局完成后才检测其是否违反规则,而不是在下棋的过程中就检测。这种方法就是真正的穷举了,效率非常低。时间复杂度是指数级的O(n^n)。
练习1.增加一个变量,记录解的个数。我已经在上面做了。
练习2.修改代码,传入一个一维列表的下棋方式,如[-1,4,-1,-1,-1,-1,-1,0],有两个位置已经下了棋了,输出可能的下棋方式。
增加一个判断,等于-1则按原来的赋值,如果不等于-1就跳过赋值,下下一列。但老也调不对。这种八个循环在一起是比较”丑”,过了。
本章代码: https://github.com/zwdnet/MyQuant/blob/master/44/04
我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。
我的个人博客地址:https://zwdnet.github.io
我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts
我的微信个人订阅号:赵瑜敏的口腔医学学习园地