1. 引言

本文为介绍流行的数独游戏的系列文章中的第一篇。更具体地说,我们如何构建一个脚本来解决数独难题,本文的重点在于介绍用于构建数独求解器的回溯算法。

数独这个名字的由来来自日语短语suuji wa dokushin ni kagiru,意思是“数字必须保持单一”。数独游戏的流行也源于其规则的简单性:数独游戏要求在 9 x 9 空间的网格上进行数字填写。在行和列中有 9 个“正方形”的格子block(由 3 x 3 个子单元格cell组成)。每一行、每一列、每一个block都需要填写数字 1-9,行、列、block内不得重复任何数字。

好的,知道了上述数独的规则,那么我们就来直接进入主体吧。 :)

2.描述数独九宫格

这一步主要为使用一组数字来初始化我们的九宫格。我们使用setBoard() 函数将输入转换为适合我们后续操作的数据类型。我们使用以下约定:

  • 空的单元格cell初始化为默认值0。
  • 维持数独谜题数字值的数据类型是一个 9x9 大小的二维列表。

这里我们的输入是一个多行字符串,我们将其处理成二维列表的形式。样例代码如下:

# Initialize a 2-D list with initial values described by the problem.
# Returns board
def setBoard():board = list()sudokuBoard = '''200080300060070084030500209000105408000000000402706000301007040720040060004010003'''rows = sudokuBoard.split('\n')for row in rows:column = list()for character in row:digit = int(character)column.append(digit)board.append(column)return board

上述代码运行后,如果展示在拼图游戏中,他的样子大概如下:

3.寻找下一个空子单元格

函数findEmpty() 函数的操作更加简单:对初始化后的九宫格作为参数传递,然后该遍历该九宫格中每一个子单元格cell,直到找到返回的第一个空的子单元格。如果没有找到空的子单元格,这表明我们的问题已解决,因此它返回None
样例代码如下:

# Find next empty space in Sudoku board and return dimensions
def findEmpty(board):for row in range(9):for col in range(9):if board[row][col] == 0 :return row,colreturn None

4. 子单元格中设置值的合法性

函数isValid()的操作是确认设定的数字是否是九宫格子单元格的有效选项。为了使设置的值满足数独九宫格的要求,该值的设置需满足以下条件:

  • 同一行的任何子单元格cell都不应包含该数字
  • 同一列的任何子单元格cell都不应包含该数字
  • 该子单元格cell所在的block不应该包含该数字

如果我们设定的值满足以上所有条件,该函数返回True,否则返回False。代码如下:

# Check whether a specific number can be used for specific dimensions
def isValid(board, num, pos):row, col = pos# Check if all row elements include this numberfor j in range(9):if board[row][j] == num:return False# Check if all column elements include this numberfor i in range(9):if board[i][col] == num:return False# Check if the number is already included in the blockrowBlockStart = 3* (row // 3)colBlockStart = 3* (col // 3)rowBlockEnd = rowBlockStart + 3colBlockEnd = colBlockStart + 3for i in range(rowBlockStart, rowBlockEnd):for j in range(colBlockStart, colBlockEnd):if board[i][j] == num:return Falsereturn True

以下是通过isValid() 函数中描述的条件后成功插入新值的动态示例:


同时,若我们引入一个与九宫格数独上已经存在的值冲突的数值,那么此时该值将不会被插入。图例如下:

5. 实现回溯算法

下一个函数是我们整个解决方案的核心思想,这里引入了回溯思想,该算法的实现步骤如下:

  • 搜索下一个空的子单元格cell。如果没有找到,那么我们已经解决了这个难题;如果没有,则转到第 2 步。
  • 通过迭代数字1-9 来猜测正确的数字,并参考已经确定的数字来检查它是否是一个合法的数字。
  • 如果找到一个有效的数字,此时递归调用solve() 函数并猜测下一个空的子单元格cell。
  • 如果数字1-9均无效,则将将子单元格cell的值重置为 0,并继续迭代以查找下一个有效数字。
# Solve Sudoku using backtracking
def solve(board):blank = findEmpty(board)if not blank:return Trueelse:row, col = blankfor i in range(1,10):if isValid(board, i, blank):board[row][col] = iif solve(board):return Trueboard[row][col] = 0return False

由于递归理解起来不是那么直观,不妨让我们尝试使用动态来将整个过程形象化:

正如我们在上面的示例中看到的那样,该算法用有效数字填充空子单元格cell,直到出现死胡同;然后它回溯,直到重新迭代该过程。

6. 性能表现

上述我们的程序需要使用回溯算法来遍历每个单元格的许多潜在值。这当然不是最优的解法,可以预想到我们的解决方法的性能会很慢。
我们使用上述代码,来解决欧拉计划的第96题中的50道数独题目,运行时间为:

The execution time of above program is : 23.56185507774353 s

好吧,确实有点慢。我们后面再来开篇讲解数独算法的优化。

7. 总结

本文讲解了数独游戏的相关规则,以及如何在Python中利用回溯思想来一步一步解决数独问题,并给出了完整的实现。

您学废了吗?

参考

关注公众号《AI算法之道》,获取更多AI算法资讯。

使用Python进行数独求解(一)相关推荐

  1. python图像数独_Python图像识别+KNN求解数独的实现

    Python-opencv+KNN求解数独 最近一直在玩数独,突发奇想实现图像识别求解数独,输入到输出平均需要0.5s. 整体思路大概就是识别出图中数字生成list,然后求解. 输入输出demo 数独 ...

  2. Python实现9x9方格数独求解小工具

    为了实现9*9方格的数独求解工具,我们需要使用Python编写程序.下面是一个简单的代码示例,可以通过命令行交互式输入和输出来实现数独求解. board = [[5, 3, 0, 0, 7, 0, 0 ...

  3. 使用Python编写数独游戏自动出题程序

    数独是一个很好玩的游戏,可以锻炼推理能力.下面的代码可以自动生成数独游戏题目. from random import shuffle, randrange def generate():     # ...

  4. 好用的z3数独求解器

    github 上发现一个好用 用z3 编写的数独求解器 传送门: https://github.com/dferri/z3-skyscrapers Generate a skyscrapers puz ...

  5. OpenCV玩九宫格数独(三):九宫格生成与数独求解

    前言 在此之前,OpenCV玩九宫格数独(一)和(二)分别介绍了如何从九宫格图片中提取出已知数字和如何用knn训练数字识别模型.在这些前期工作都已经完成的基础上,接下来我们需要做什么呢? 我们要做的有 ...

  6. 利用全连接网络实现数独求解

    [摘要] 本文介绍了一个能够求解数独问题的求解器的设计与实现,该求解器具备多种功能.它可以通过识别图片中的数独网格,也可以随机生成数独题目,识别数独题目:对数独进行验证.提示,并能展示求解过程的算法演 ...

  7. 数独求解算法_我如何回到一个老问题,终于写了一个数独求解算法

    数独求解算法 by Ali Spittel 通过Ali Spittel 我如何回到一个老问题,终于写了一个数独求解算法 (How I came back to an old problem and f ...

  8. 《Python智能数独说明书》源码下载...

    <Python智能数独说明书> 如需获取原文档:公众号回复Python智能数独说明书. 文章目录 <Python智能数独说明书> 一.需求分析 1.1技术现状 1.2题目阐述 ...

  9. delphi dbgrideh 遍历每一个单元格_用Python解数独[1]:求每个单元格的行值域

    目录 用Python解数独[0] 用Python解数独[1]:求每个单元格的行值域 用Python解数独[2]:求列值域和九宫格值域 用Python解数独[3]:求总值域 用Python解数独[4]: ...

  10. python deepcopy函数_用Python解数独[6]:递归获得最终答案

    目录 用Python解数独[0] 用Python解数独[1]:求每个单元格的行值域 用Python解数独[2]:求列值域和九宫格值域 用Python解数独[3]:求总值域 用Python解数独[4]: ...

最新文章

  1. 【Linux 内核】CFS 调度器 ② ( CFS 调度器 “ 权重 “ 概念 | CFS 调度器调度实例 | 计算进程 “ 实际运行时间 “ )
  2. UA MATH565C 随机微分方程III Ito Isometry
  3. 【Linux】一步一步学Linux——arp命令(163)
  4. centos6 nodejs 安装测试
  5. 检查是否禁止asp.net服务扩展_在 Kubernetes 环境下部署 OpenWhisk 服务
  6. 【Elasticsearch】在 Elasticsearch 中每秒存储 5000 万个事件:我们是如何做到的
  7. C语言常用8种排序方法耗时测试
  8. extjs4 grid 刷新数据时不改变滚动条位置
  9. Centos 7 Puppet之foreman介绍安装测试
  10. 获得执行计划方法三-sql_trace
  11. phpstorm连接不上MySQL_PHPStorm无法连接到本地MySQL [重复]
  12. 部署Azkaban多节点分布式模式
  13. Anaconda版本与Python版本对应关系
  14. Apache网页与安全优化(网页压缩、网页缓存、隐藏版本信息、网页图片防盗链)——理论+实验!超详细
  15. cad小插件文字刷_cad插件-文本修改
  16. ln多少等于2用计算机,ln2(log计算器在线)
  17. 串口服务器的作用是什么?
  18. 在数据库中存储IP地址
  19. 微信小程序例子——使用icon组件显示常用图标
  20. jQuery——小案例:点击图片放大缩小

热门文章

  1. C++模拟手机通信录管理系统
  2. Go 依赖管理工具 Dep 的安装及配置
  3. 降低软件复杂性的一般原则和方法
  4. 『代码之外』用经济学利息的角度看美债倒挂
  5. 【FXCG】美国加息缩表在即,人民币仍创新高
  6. linux的内存available,Linux中available内存的计算
  7. 必备的查询网址:查征信、婚姻、交友借钱明明白白
  8. excel两列数据对比找不同_Excel小白就不能用数据分析的办法找工作吗?
  9. 微信公众号管理欧宁泰php,米拓微信公众号管理应用-MetInfo帮助中心
  10. RabbitMQ的ack与nack