Python----递归------Eight Queens 八皇后问题
递归思想是算法编程中的重要思想。
作为初学者,对递归编程表示很蒙逼,每次遇到需要递归的问题,心里就有一万头草泥马飞过~~~~~~(此处略去一万头草泥马)
在B站看数据结构与算法的视频时,视频中给了两个非常典型的例子——《汉诺塔》和《八皇后问题》,就希望自己用Python实现一下这两个递归程序,其中汉诺塔问题比较简单,还是能够理解,这里就不讲了。
《八皇后问题》:说要在一个棋盘上放置8个皇后,但是不能发生战争,皇后们都小心眼,都爱争风吃醋,如果有人和自己在一条线上(水平、垂直、对角线)就会引发撕13大战,所以我们就是要妥当的安排8位娘娘,以保后宫太平。[1]
与网上普遍搜到的利用yield函数完成递归方法不同,注意时因为对于初学Python的我来说,完全搞不懂yield怎么用,更不要说将其放在递归程序里了, [捂脸]
下面我会对我的代码进行逐一解释,希望更多的像我这样的初学者能够看懂。!!!敲黑板!!!------------不仅要看懂,还要自己会写代码-----------------
首先声明:
代码中位置状况采用list列表的形式, 如,chess[0] = 4代表在棋盘第1行的第5个位置放置皇后。
count = 0 # 定义一个全局变量count, 用于八皇后方案的统计 # conflict 函数为冲突函数,主要用于判断新添加的位置是否与前面的位置冲突
# pos 为新添加的位置, chess为添加pos位置前的皇后位置分布
def conflict(pos, chess):
len_chess = len(chess) # 现在已经分配了几行,几有几个皇后在棋盘上,因为初始chess为空,每次判断一个符合规则的位置后再加入到棋盘中
for i in range(len_chess):if abs(chess[i] - pos) in (0, len_chess - i): # 这一行为关键,太多了就放后面了
return True
return False # Queen函数为递归函数
def Queens(num,chess):
global count # python 中要再函数中使用之前定义的全局变量,必须再函数中用 global 声明一下 if len(chess) == 8: # 判断chess的长度,当chess长度为8的时候,说明8个皇后都已经全部放好位置了,就可以直接输出相应的方案了
count += 1
print(chess)
else: # chess长度小于8,说明还有没安排好的皇后,所以继续安排剩下的位置
for pos in range(num): # 对接下来的一行的8个位置进行遍历
if not conflict(pos, chess): # 对每个位置进行冲突判断
chess1 = [] #关键是这三行,用于构造棋盘的副本,这三句非常重要,具体原因放在后面解释
for i in chess:
chess1.append(i)
chess1.append(pos) # 符合规则,则将其附在chess副本的后面
Queens(num,chess1) # 递归调用Queens函数 board = [] # 初始化空棋盘
Queens(8,board) # 调用函数
print(count) # 打印总共有多少中方案
冲突判断
def conflict(pos, chess):
len_chess = len(chess) # 现在已经分配了几行,几有几个皇后在棋盘上,因为初始chess为空,每次判断一个符合规则的位置后再加入到棋盘中
for i in range(len_chess):if abs(chess[i] - pos) in (0, len_chess - i): # 这一行为关键,太多了就放后面了
return True
return False
根据规则:有三种情况存在冲突,我i们一一来列举分析一下:
- 在同一列的情况,若两个皇后在同一列,那么这两行的纵坐标相同,反映到我们的棋盘定义上则未:chess[i] = chess[j] 即第i行与第j行的两个皇后在同一列了
- 第二种情况则为在“\” 对角线上,那么各位置的(横坐标 - 纵坐标)的值时一样的,假设chess[i] = a1,chess[j] = a2在对角线"\"上,i - a1 = j - a2。 如(0,1),(1,2),(2,3)横纵坐标之差都为1
- 第三种情况则为在" / " 对角线上,那么各位置的(横坐标 + 纵坐标)的值时一样的,假设chess[i] = a1,chess[j] = a2在对角线"\"上,i + a1 = j + a2。 如(0,3),(1,2),(2,1)横纵坐标之和都为1
我们再观察,就会发现(这个我自己想时想不出来的,也是对照着代码思考出来的):
对于被判断是否符合要求的元素,其索引恰好为现在chess的长度,因为最后一个元素的索引为len(chess)-1,那么新的元素的索引恰为len(chess)
我们另 len_chess 为当前chess的长度,则三种情况对应的表达式为:
- chess[i] - pos = 0
- chess[i] - i = pos - len_chess ---------> chess[i] - pos = i-len_chess
- chess[i] + i = pos + len_chess ---------> chess[i] - pos = len_chess - i
由于 len_chess > i, 所以可以得到当abs(chess[i] - pos)==0 或len_chess - i时则不符合规则,返回True :
棋盘副本建立
for pos in range(num): #对接下来的一行的8个位置进行遍历
if not conflict(pos, chess): #对每个位置进行冲突判断
chess1 = [] #关键是这三行,用于构造棋盘的副本,这三句非常重要,具体原因放在后面解释
for i in chess:
chess1.append(i)
chess1.append(pos) # 符合规则,则将其附在chess副本的后面
Queens(num,chess1) # 递归调用Queens函数
这里首先提一点的是,python里面所有如果要将一个list拷贝一份,不能直接像C语言里面一样用幅值语句,需要重新初化,
我个人的理解是:因为list的名称为一个地址,当我们将一个地址幅值给一个新的变量时,新的变量指向的还是原来那个数组,所以并没有起到拷贝的作用。 比较典型的例子就是规定大小的二维数组的建立
言归正传,我们为什么要新建立一个副本呢?
- 因为我们需要使用副本来进行深层次的递归,如果不使用副本chess1而直接使用原始数据chess,那么随着递归的深入,chess所对应的地址内的值在不断变化,当返回到递归点的时候,原始数据已经不存在了,
只会从当前chess对应的数组继续进行递归。
- 比如,当 chess = [0,2,4,1,3]时,此时我们需要填充第6行皇后的位置,但是通过判断,发现第6行所有位置都不符合要求,那么此时程序应该退回chess = [0,2,4,1,4]再继续判断第6行是否有符合的位置,但是若不用副本
的话,程序会退回,但是chess所对应的值还是[0,2,4,1,3],这样是错误的。
QAQ: 这一段我也没有讲的特别清楚,主要关键就是这个副本的建立使原始数据不受破坏,可以在递归从深层跳出的时候保持为原来的状态继续进行,可以在编译器中单步运行看一看再理解会更好
[1]. 摘自http://www.cnblogs.com/littleseven/p/5362791.html, 斯认为该博主写的还可以,
Python----递归------Eight Queens 八皇后问题的更多相关文章
- [CareerCup] 9.9 Eight Queens 八皇后问题
9.9 Write an algorithm to print all ways of arranging eight queens on an 8x8 chess board so that non ...
- C#中八皇后问题的递归解法——N皇后
百度测试部2015年10月份的面试题之——八皇后. 八皇后问题的介绍在此.以下是用递归思想实现八皇后-N皇后. 代码如下: using System;using System.Collections. ...
- java递归求八皇后问题解法
八皇后问题 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处 ...
- 八皇后,回溯与递归(Python实现)
八皇后问题是十九世纪著名的数学家高斯1850年提出 .以下为python语句的八皇后代码,摘自<Python基础教程>,代码相对于其他语言,来得短小且一次性可以打印出92种结果.同时可以扩 ...
- 【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)
八皇后问题是一道经典的回溯问题.问题描述如下:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8*8个方格),使它们谁也不能被吃掉? 看到这个问题,最容易想 ...
- Python解决八皇后问题的代码【解读】
八皇后问题 来自于西方象棋(现在叫 国际象棋,英文chess),详情可见百度百科. 在西方象棋中,有一种叫做皇后的棋子,在棋盘上,如果双方的皇后在同一行.同一列或同一斜线上,就会互相攻击. 八皇后问题 ...
- python基础教程总结8——特殊方法,属性,迭代器,生成器,八皇后问题
1. 重写一般方法和特殊的构造方法 1.1 如果一个方法在B类的一个实例中被调用(或一个属性被访问),但在B类中没有找到该方法,那么会去它的超类A里面找. class A: ... def hello ...
- LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天我们讲的是LeetCode的31题,这是一道非常经典的问题,经常会在面试当中遇到.在今天的文章当中除了关于题目的分析和解答之外,我们还会 ...
- Python学习二(生成器和八皇后算法)
看书看到迭代器和生成器了,一般的使用是没什么问题的,不过很多时候并不能用的很习惯 书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个ugly的代码 ...
随机推荐
- Servlet-SrpingMVC 生成验证码
在SpringMVC中配置生成验证码: import org.springframework.stereotype.Controller; import org.springframework.web ...
- Fragmen的onAttach方法
现在Android开发多使用一个Activity管理多个Fragment进行开发,不免需要两者相互传递数据,一般是给Fragment添加回调接口,让Activity继承并实现. 回调接口一般都写在Fr ...
- 通过代码获取log4net的文件路径
http://stackoverflow.com/questions/1343749/get-log4net-log-file-in-c-sharp Solution is quite easy in ...
- JZOJ 1003 [ 东莞市选 2007 ] 拦截导弹 —— 递推
题目:https://jzoj.net/senior/#main/show/1003 n^2 的话递推就可以啦. 代码如下: #include<iostream> #include< ...
- bzoj2194
http://www.lydsy.com/JudgeOnline/problem.php?id=2194 卷积... 卷积并不高深,其实卷积就是两个多项式相乘的系数,但是得满足一点条件,就是f[n]= ...
- android 中activity 属性说明(转载)
转自:http://liuwuhen.iteye.com/blog/1759796 activity是android中使用非常平凡的一种组件,我们除了需要掌握activity中的生命周期以外,还需要掌 ...
- 用JavaScript实现歌词滚动播放
各种音乐播放器上都有一个自动滚动播放歌词的功能,那么这个功能用JavaScript怎么实现呢?请看下文. 一般音乐播放器使用的歌词格式都是lrc,为了方便处理,我们这里使用XML格式的歌词.介绍一个网 ...
- 网络简要<入门篇>
OSI七层 网络的含义:两个不在同一地理位置的主机(终端),通过传输介质和通信协议,实现通信和资源共享. 网络四要素:终端,传输介质 ,通信协议,资源 网络分类: 以范围分类:LAN网(局域网,以太网 ...
- DFS知识点
2019-06-01 11:14:34 加油,坚持!!! 1. 2. 3.
- CF 351A - Jeff and Rounding DP
http://codeforces.com/problemset/problem/351/C 题意:有2*n个浮点数a1,a2,a3...a2*n,把他们分成n队,对于每对<A,B>,对A ...