使用Python进行数独求解详解(一)
作者:赵卓不凡 发布时间:2023-12-25 09:39:20
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 = '''
200080300
060070084
030500209
000105408
000000000
402706000
301007040
720040060
004010003
'''
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,col
return 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 number
for j in range(9):
if board[row][j] == num:
return False
# Check if all column elements include this number
for i in range(9):
if board[i][col] == num:
return False
# Check if the number is already included in the block
rowBlockStart = 3* (row // 3)
colBlockStart = 3* (col // 3)
rowBlockEnd = rowBlockStart + 3
colBlockEnd = colBlockStart + 3
for i in range(rowBlockStart, rowBlockEnd):
for j in range(colBlockStart, colBlockEnd):
if board[i][j] == num:
return False
return 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 True
else:
row, col = blank
for i in range(1,10):
if isValid(board, i, blank):
board[row][col] = i
if solve(board):
return True
board[row][col] = 0
return False
由于递归理解起来不是那么直观,不妨让我们尝试使用动态来将整个过程形象化:
正如我们在上面的示例中看到的那样,该算法用有效数字填充空子单元格cell,直到出现死胡同;然后它回溯,直到重新迭代该过程。
6. 性能表现
上述我们的程序需要使用回溯算法来遍历每个单元格的许多潜在值。这当然不是最优的解法,可以预想到我们的解决方法的性能会很慢。
我们使用上述代码,来解决欧拉计划的第96题中的50道数独题目,运行时间为:
The execution time of above program is : 23.56185507774353 s
好吧,确实有点慢。我们后面再来开篇讲解数独算法的优化。
7. 总结
本文讲解了数独游戏的相关规则,以及如何在Python中利用回溯思想来一步一步解决数独问题,并给出了完整的实现。
来源:https://blog.csdn.net/sgzqc/article/details/122992189


猜你喜欢
- 本文实例讲述了Python使用Pandas库常见操作。分享给大家供大家参考,具体如下:1、概述Pandas 是Python的核心数据分析支持
- 第一次做完主从库同步后正常,但工作过程中发现有一个库的数据库没有同步起来,在另外一个mysql(3307)中于是:1、在主库中创建一个临时库
- 本文实例总结了PHP session会话操作技巧。分享给大家供大家参考,具体如下:会话技术session将会话数据存储与服务器端,同时使会话
- 一开始的目的是学习十大挖掘算法(机器学习算法),并用编码实现一遍,但越往后学习,越往后实现编码,越发现自己的编码水平低下,学习能力低。这一个
- 对一名开发者来说最糟糕的情况,莫过于要弄清楚一个不熟悉的应用为何不工作。有时候,你甚至不知道系统运行,是否跟原始设计一致。在线运行的应用就是
- 本文实例为大家分享了python读取mysql数据绘制条形图的具体代码,供大家参考,具体内容如下Mysql 脚本示例:create tabl
- 虽然在win2003配置PHP有点非主流,但你还是要会怎么弄。你也可以将本文的虚拟机看成是服务器,宿主机看成是客户端。不像Linux系统,由
- 今天在使用Pycharm的时候,由于文件过多,我对目录下的文件做了归类,改动了一些文件的路径,结果后来执行的时候,出现了路径找不到的错误.新
- 前言本文将教你如何使用YOLOV3对象检测器、OpenCV和Python实现对图像和视频流的检测。用到的文件有yolov3.weights、
- 开发中经常会使用npm install 安装依赖包,经常会看到^符号和~符号,现将二者的区别总结如下:版本号 x.y.z : z
- 本文实例讲述了Thinkphp 框架基础之源码获取、环境要求与目录结构。分享给大家供大家参考,具体如下:获取ThinkPHP获取ThinkP
- 理论傅立叶变换用于分析各种滤波器的频率特性,对于图像,2D离散傅里叶变换(DFT)用于找到频域.快速傅里叶变换(FFT)的快速算法用于计算D
- 介绍图像分类器通常在训练更多的图像时表现得更好。在图像分类模型中,一个常见的问题是,模型不能正确地对图像进行分类,只是因为它没有针对同一图像
- 网上看到一些例子,对于一个简单的3 级联动,都加上什么Struts, Hibernate诸如此类的框架。这个Ajax联动殊不知和这些框架有什
- 事务特性1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。2、一致性(Consiste
- 查看安装的python版本号可以使用【python --version】命令。具体方法:首先按【win+r】组合键打开运行;然后输入cmd,
- 0.引言利用python开发,借助Dlib库进行人脸识别,然后将检测到的人脸剪切下来,依次排序显示在新的图像上;实现的效果如下图所示,将图1
- 傅里叶变换dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)傅里叶逆变换
- 0.目录1.遇到的问题2.创建二维数组的办法•3.1 直接创建法•3.2 列表生成式法•3.3 使用模块numpy创建1.遇到的问题今天写P
- 起步要介绍一个非常方便的 Django 扩展包-- django-hosts 。它能够提供在不同的子域名下访问不同的 app。例如,在项目中