使用Python进行数独求解详解(二)
作者:赵卓不凡 发布时间:2023-02-25 22:33:41
1. 引言
本文是数独游戏问题求解的第二篇,在前文中我们使用回溯算法实现了最简单版本的数独游戏求解方案。本文主要在前文解决方案的基础上,来思考如何通过改进来提升数独问题求解算法的性能。
闲话少说,我们直接开始吧。 :)
2. 前文回顾
我们首先来回顾下前文的回溯算法,如下图示:
在前文中,我们引入了回溯算法来对数独问题求解,通过迭代每个子单元格cell的所有可能取值来暴力解决该问题,直到引入数独九宫格中的新值与属于同一行,列或block块的子单元格中确定值之间没有冲突为止。这种解决方案虽然可以有效解决该问题,但是它绝对不是最佳的解决方案,因为它没有合理利用数独九宫格中提供的附加先验信息。下面,我们来一步步对前文算法进行优化吧。。。
3. 减少非比要的迭代次数
优化上述算法的第一个想法来自于这样的观察,我们的算法按顺序迭代所有数字1到9,直到它找到一个与已经包含相同值的同一行,列或block块中的另一个单元格不冲突的值。但是,数独九宫格中一些确定值会已经为我们提供了一些信息,说明哪些数字不可能添加到某个子单元格cell中。
# 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
我们优化的思路是首先扫描我们的数独九宫格,将每个子单元格的所有可能的合法候选值保存在内存中然后再逐个迭代它们,而不是迭代所有数字。参考下图,演示了数独九宫格的 2 个子单元格的候选值的集合。正如我们的游戏规则所暗示的那样,每行,每列和每个block块不能包含相同的数字,因此在属于给定子单元格的同一行,列和所属block块的单元格中已经确定的所有数字都被排除在外。
既然有了优化思路,那么我们接下来就可以来用代码实现上述想法啦.
3.1 生成候选值字典
接着我们需要一个数据结构(这里我们选用字典)来保存每个子单元格的候选值列表,该函数通过遍历整个九宫格中空的子单元格并调用我们的allowedValues()函数来返回子单元格的候选值列表.
样例代码如下:
# Store in a dictionary the legitimate
# values for each individual cell
def cacheValidValues(board):
cache = dict()
for i in range(9):
for j in range(9):
if board[i][j] == 0:
cache[(i,j)] = allowedValues(board,i,j)
return cache
3.2 生成候选值列表
在上小节中的allowValues() 函数与我们在前篇文中看到的isValid() 函数具有类似的逻辑,但在本例中,它返回值为每个子单元格所提取到的合法数字的列表。
样例代码如下:
def allowedValues(board,row,col):
numbersList = list()
for number in range(1,10):
found = False
# Check if all row elements include this number
for j in range(9):
if board[row][j] == number:
found = True
break
# Check if all column elements include this number
if found == True:
continue
else:
for i in range(9):
if board[i][col] == number:
found = True
break
# Check if the number is already included in the block
if found == True:
continue
else:
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] == number:
found = True
break
if found == False:
numbersList.append(number)
return numbersList
3.3 函数调用
有了我们的单元格候选值缓存字典,下面我们准备测试该方案是否会显着提高我们的程序性能。
为此我们还需要将 solve() 函数替换为一个新的函数solveWithCache(),该函数只迭代每个子单元格cell的合法值列表,而不是所有数字 1–9。
代码如下:
def solveWithCache(board, cache):
blank = findEmpty(board)
if not blank:
return True
else:
row, col = blank
for value in cache[(row,col)]:
if isValid(board, value, blank):
board[row][col] = value
if solveWithCache(board, cache):
return True
board[row][col] = 0
return False
在实现所有改动后测试我们的代码为我们提供了所需的结果,与我们的第一个版本相比,跑同样50组测试用例执行时间明显缩短:
The execution time of above program is : 15.41820478439331 s
4. 总结
本文为数独游戏求解的第二篇,主要基于第一篇的回溯思想来思考如何利用数独九宫格的先验思想来减少回溯的迭代次数,进而提升算法提升效率,并给出了完整代码实现.
来源:https://blog.csdn.net/sgzqc/article/details/123015338


猜你喜欢
- nginx简单配置php服务(多个)摘要:大部分网站开发语言都要运行在服务器,比如主流的nginx、apache等等,部署服务器环境对于大部
- 前言记得刚入门那个时候,自己处理编码转换问题往往是“百度:url解码、base64加密、hex……”,或者是使用一款叫做“小葵多功能转换工具
- 随着因特网的发展,在网络环境中,数据库应用渐渐向操作简单、功能实用的方向发展。本文介绍如何利用ASP技术实现对数据库进行在线维护的方法,并给
- 本文实例总结了MySQL单表查询常见操作。分享给大家供大家参考,具体如下:创建fruits表:CREATE TABLE fruits( f_
- 有时引用其它js时,其js却使用了window.onload事件,这样的话,引入的页面的onload事件就有可能执行不了,怎样才能两个都运行
- 数据库镜像方案有两种镜像运行模式。一种是“高安全性模式”,它支持同步操作。在高安全性模式下,当会话开
- 前言最近在学习python,学习到了一个之前没接触过的--特殊方法。什么是特殊方法?当我们在设计一个类的时候,python中有一个用于初始化
- 前言这篇博文发布后,有朋友问有没有SQL server版本的,现在有了==》传送门一、场景再现在一个erp进销存系统或0A等其他系统中,如果
- SQLserver 2014 AlwaysOn增强了原有的数据库镜像功能,使得先前的单一数据库故障转移变成以组(多个数据)为单位的故障转移。
- 实现一个不规则窗体这里我们实现一个圆形窗体,实现其他形状的窗体与这个方法类似。首先,把窗口的高度(height)和宽度(width)值修改为
- 本文实例讲述了Python3中的真除和Floor除法用法。分享给大家供大家参考,具体如下:在Python3中,除法运算有两种,一种是真除,一
- 添加用户(随着用户的创建,自动产生与用户同名的schema) CREATE USER "TESTER" PROFILE
- 前言SPA项目中,首屏加载速度都是老生常谈的问题了,首屏时间直接反应了用户多久能看到页面的主要内容,这决定了用户体验,本文聊一聊如何采集首屏
- 1.查询当前年、月、周相关时间1.1.查询当前年份SELECT TO_CHAR(SYSDATE,'YYYY') AS YEA
- 目录1. lru_cache的使用1.1 参数详解1.2 基本用法1.3 进阶用法2. functiontools.wrap装饰器对lru_
- 简介一款跨平台/无依赖的自动化测试工具,目测只能控制鼠标/键盘/获取屏幕尺寸/弹出消息框/截屏。安装pip install pyautogu
- 马上就要过节了,想把自己的项目搞得酷炫一些,对整个网站的按钮添加图标、飘花效果、首屏大图展示、顶部导航背景图,于是就写了这一遍文字,如有兴趣
- 最近写了一些python3程序,四处能看到bytes类型,而它并不存在于python2中,这也是python3和python2显著区别之一。
- 序言哈喽兄弟们,今天来实现一个Python采集视频、弹幕、评论与一体的小软件。平常咱们都是直接代码运行,不过今天我们做成软件,这样的话,咱们
- Microsoft SQL Server 2008通过与Microsoft Office的深度集成,为所有人提供了可用的商业智能,以合适的价