八皇后问题 来自于西方象棋(现在叫 国际象棋,英文chess),详情可见百度百科

在西方象棋中,有一种叫做皇后的棋子,在棋盘上,如果双方的皇后在同一行、同一列或同一斜线上,就会互相攻击。

八皇后问题:

在8行8列的棋盘上摆放8个皇后,使之不能互相攻击——任意两个不在同一行、同一列或同一斜线上。

Level 1:找到一种摆放的方法

Level 2:找到总共有多少种方法

----------

下面展示在《Python基础教程》(第二版·修订版)中看到的解法,本文的目的是对其进行解读,加深自己的理解(今天花了一个多钟想明白)。

应用到的重要技术:生成器、递归算法

解决方法:

Step 1-定义冲突函数

在当前行的8个位置摆放棋子时,检查是否与已摆放的棋子是否冲突。

def conflict(state, nextX):                            #state为已摆放的棋子的位置的元组,比如(1,3,0)
nextY = len(state) #获取当前行号
for i in range(nextY): #检查每一个已摆放的棋子和当前行要摆放的棋子的位置(nextX, nextY)是否冲突
if abs(state[i] - nextX) in (0, nextY - i): #关键!若是两个棋子 行差值 的绝对值 出现在元组 (0,行差值)中,则冲突发生,返回True
return True
return False #无冲突,可行的摆放位置

Step 2-递归实现寻找摆放方案

八皇后问题,是否可以拆解为七皇后问题,再拆解为六皇后问题,再……一皇后问题?可以。不过,一皇后、二皇后、三皇后问题都是没有解决方案的。

在摆放最后一个棋子时,前面的棋子已经没有冲突了,那么,最后一步,依次检查在最后一行的每个位置摆放棋子是否和已摆放的棋子是否冲突,如果

不冲突,那么,一种解决方案就有了——递归的终结(书中叫做 基本情况)。

def queens(num=8, state=()):                               #num为棋盘的行数,state为已摆放的棋子的列数汇总,类型为 元组
if len(state) == num - 1: #检查是否最后一行,如果是最后一行,则执行终极操作,不再递归
for pos in range(num): #pos从 0 到 棋盘行数 - 1
if not conflict(state, pos): #检查是否冲突
yield (pos,) #没有冲突,返回列数的元组
else: #不是最后一行
for pos in range(num): #检查当前行每一个列的位置
if not conflict(state, pos): #检查是否有冲突
for result in queens(num, state + (pos,)): #递归调用queens,不过找到了更多的一行的摆放位置,所以,加上(pos,)
#如果是最后一行,返回一个数字的元组,比如,(2)
#此时,如果pos为0,那么,倒数第二行返回的为两个数字的元组,比如,(0, 2)
#调用每返回一层,返回的元组的长度就加1,直到最后用户在外部调用queens的位置
#返回所有行的皇后位置的 元组,其长度为行数
yield (pos,) + result #这里和想象的有些不同,下面是在Python 2.7.14上运行代码发生的错误
#程序执行后没问题,可是~~看来还没想明白!(下面有进一步分析)

queens(...)返回的是一个迭代器(生成器 更准确!生成器就是一种迭代器!),因此,下面代码中的result是一个元组,而不是一个数值:

for result in queens(num, state + (pos,))

这样,(pos,) + result就解释的通了!啊哈,明白了!

可以在yield语句上添加打印语句,可以更好地帮助分析。上面想不通的原因在于,将queens(...)返回的内容的类型搞错了,也是不了解

生成器的原理所致,现在理解更深刻啦。

代码改进:

在上面第二份代码中,两个分支中的红色部分是完全相同的,因此,可以对代码进行简化,下面是简化结果。

def queens2(num=8, state=()):
for pos in range(num): #重复部分
if not conflict(state, pos): #重复部分
if len(state) == num - 1: #分支1
yield (pos,)
else: #分支2
for result in queens(num, state + (pos,)):
yield (pos,) + result

执行结果:

----------

在2.7.14中执行下面的代码发生错误了:试验上面搞不明白的问题

Python解决八皇后问题的代码【解读】的更多相关文章

  1. Python解决八皇后问题

    最近看Python看得都不用tab键了,哈哈.今天看了一个经典问题--八皇后问题,说实话,以前学C.C++的时候有这个问题,但是当时不爱学,没搞会,后来算法课上又碰到,只是学会了思想,应该是学回溯法的 ...

  2. Python 解决八皇后问题

    问题介绍 八皇后问题是一个以国际象棋为背景的问题:如何能够在 \(8\times8\) 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一 ...

  3. python解决八皇后问题的方法

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/9/11 15:40 # @Author : Lijinjin # @Site ...

  4. C语言解决八皇后问题

    #include <stdio.h> #include <stdlib.h> /* this code is used to cope with the problem of ...

  5. 使用穷举法结合numpy解决八皇后问题

    一般说到八皇后问题,最先想到的就是回溯思想,而回溯思想往往是需要递归来实现的. 计算机很善长做重复的事情,所以递归正和它的胃口,而我们人脑更喜观平铺直叙的思维方式.当 我们看到递归时,总想把递归平铺展 ...

  6. 回溯算法-C#语言解决八皇后问题的写法与优化

    结合问题说方案,首先先说问题: 八皇后问题:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 嗯,这个问题已经被使用各种语言解 ...

  7. 八行代码解决八皇后问题(c++)

    说的有点夸装,实际上并不只是巴航代码,加上前面的变量声明之类的一共有40多行的样子吧,好像是在知乎上看到的,现在有时间再把它写下来: 其中用到了一些c++11特性,例如lambda 以及给予范围的 f ...

  8. python学习八皇后问题

    0 # -*- coding: utf-8 -*- 1 import random #冲突检查,在定义state时,采用state来标志每个皇后的位置,其中索引用来表示横坐标,基对应的值表示纵坐标,例 ...

  9. python实现八皇后问题

    import random def judge(state, nextX): #判断是否和之前的皇后状态有冲突 nextY = len(state) for i in range(nextY): if ...

随机推荐

  1. JDK中的SimpleDateFormat线程非安全

    在JDK中使用SimpleDateFormat的时候都会遇到线程安全的问题,在JDK文档中也说明了该类是线程非安全的,建议对于每个线程都创建一个SimpleDateFormat对象.如下面一个Case ...

  2. BZOJ 50题纪念?

    是的,这次的纪念帖也比较磕碜-- 但是还有更磕碜的↓↓↓ 2017年6月7日,我在我的旧博客发了个bzoj10题纪念-- 那时我还是一个又young又simple的菜鸡(现在可能也是--),省选之后觉 ...

  3. 【spoj NSUBSTR】 Substrings

    http://www.spoj.com/problems/NSUBSTR/ (题目链接) 题意 给出一个字符串S,令${F(x)}$表示S的所有长度为x的子串出现次数的最大值.求${F(1)..... ...

  4. debian修改时区

    这里提供两种方法 一.使用dpkg-reconfigure修改 # dpkg-reconfigure tzdata Current default time zone: 'Asia/Shanghai' ...

  5. Service Intent must be explicit的解决方法

    今天遇到如标题问题,查阅资料:http://blog.android-develop.com/2014/10/android-l-api-21-javalangillegalargumen.html ...

  6. PHP_EOL 写入字符串换行 , php获取毫秒 microtime

    private function miclog($t1,$t2,$name){ $lasttime = ($t2 - $t1).'ms'; $content = date('Y-m-d H:i:s', ...

  7. STL中的优先级队列priority_queue

    priority_queue(queue类似)完全以底部容器为根据,再加上二叉堆(大根堆或者小根堆)的实现原理,所以其实现非常简单,缺省情况下priority_queue以vector作为底部容器.另 ...

  8. python基础之字符串格式化

    python中字符串格式化有两种,一种是%,另一种是str中的format()功能. % 列举格式符 %s    字符串 %c    单个字符 %b    二进制整数 %d    十进制整数 %i   ...

  9. Ansible12:lookup

    目录 简单说明 1.file 2.pipe 3.env 4.template 5.csvfile 6.redis_kv 7.etcd 8.password 9.dnstxt 简单说明 在通常情况下,所 ...

  10. 数据分析与展示---Matplotlib基本绘图函数

    一:基本绘图函数(这里介绍16个,还有许多其他的) 二:pyplot饼图plt.pie的绘制 三:pyplot直方图plt.hist的绘制 (一)修改第二个参数bins:代表直方图的个数,均分为多段, ...