用 Python 解数独(Sudoku)

article/2025/10/2 2:24:10

芬兰数学家因卡拉花费3个月时间设计出的世界上迄今难度最大的数独。数独是 9 横 9 竖共有 81 个格子,同时又分为 9 个九宫格。规则很简单:每个空格填入 1~9 任意一个数字,需要保证每个横排和竖排以及九宫格内无相同数字。

在这里插入图片描述

解数独是一个可有可无的爱好,知道这个益智游戏,但是不很上心。但是前两天,由于自己的学生装了一个 ubuntu 18.04 的系统,上面有一些数独游戏,偶然间,让我看见了,为了更好的显摆自己的 Python 知识,决定用 Python 写一个程序,所以就有了下面的文字。

1、将待解的数独转换成 Python 矩阵

m = [[6, 0, 0, 1, 0, 0, 7, 0, 8],[0, 0, 0, 8, 0, 0, 2, 0, 0],[2, 3, 8, 0, 5, 0, 1, 0, 0],[0, 0, 0, 0, 4, 0, 0, 9, 2],[0, 0, 4, 3, 0, 8, 6, 0, 0],[3, 7, 0, 0, 1, 0, 0, 0, 0],[0, 0, 3, 0, 7, 0, 5, 2, 6],[0, 0, 2, 0, 0, 4, 0, 0, 0],[9, 0, 7, 0, 0, 6, 0, 0, 4]
]

就是这么简单,将待填写的空白格用 0 来代替。

2、寻找第一个空格位置

def start_pos(m:"数独矩阵"):""" 功能:返回第一个空白格的位置坐标"""for x in range(9):for y in range(9):if m[x][y] == 0:return x, yreturn False, False  # 若数独已完成,则返回 False, False

找到 Python 矩阵中第一个是 0 的元素的位置坐标。

3、寻找下一个空格位置

def get_next(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:获得下一个空白格在数独中的坐标。       """for next_x in range(x, 9):  for next_y in range(0, 9):if m[next_x][next_y] == 0:return next_x, next_yreturn -1, -1               # 若不存在下一个空白格,则返回 -1,-1

找到 Python 矩阵中下一个是 0 的元素的位置坐标。详细内容看注释。

4、寻找适合当前空格的数字的集合

def value(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:返回符合"每个横排和竖排以及九宫格内无相同数字"这个条件的有效值。""" i, j = x//3, y//3grid = [m[i*3+r][j*3+c] for r in range(3) for c in range(3)]v = set([x for x in range(1,10)]) - set(grid) - set(m[x]) - \set(list(zip(*m))[y])return list(v)

每个空格可以填入 1~9 中的任意一个数字,但要符合规则:每个空格填入 1~9 任意一个数字,需要保证每个横排和竖排以及九宫格内无相同数字。下面的代码中的 grid 变量,保存的是当前位置所处的九宫格。v 变量是通过集合运算,将 1~9 这个数字集合中,与行的数字集合、列的数字集合以及九宫格的数字集合重叠的部分去除掉。剩余的部分就是符合条件的数字的集合。

5、使用递归尝试解数独(Sudoku)

def try_sudoku(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:试着填写数独 """for v in value(m, x, y):m[x][y] = vnext_x, next_y = get_next(m, x, y)if next_y == -1: # 如果无下一个空白格return Trueelse:end = try_sudoku(m, next_x, next_y) # 递归if end:   # 数独解完之后,此处的 end 会是 Truereturn Truem[x][y] = 0 # 在递归的过程中,如果数独没有解开,# 则回溯到上一个空白格

详细内容看注释。

6、代码展示

""" 数独是 9 横 9 竖共有 81 个格子,同时又分为 9 个九宫格。我们填写数独的顺序是将 9 个九宫格按照从左到右,从上到下的顺序排列,再将每个九宫格内部的空白格按照从左到右,从上到下的顺序排列,依次按照顺序填写空白格。"""""" 解此种数独用达不到默认递归的深度
import sys  
sys.setrecursionlimit(100000) # 发现python默认的递归深度是很有限的#(默认是1000),因此当递归深度超过999的# 样子,就会引发这样的一个异常。
"""def get_next(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:获得下一个空白格在数独中的坐标。       """for next_y in range(y+1, 9):  # 下一个空白格和当前格在一行的情况if m[x][next_y] == 0:return x, next_yfor next_x in range(x+1, 9):  # 下一个空白格和当前格不在一行的情况for next_y in range(0, 9):if m[next_x][next_y] == 0:return next_x, next_yreturn -1, -1               # 若不存在下一个空白格,则返回 -1,-1def value(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:返回符合"每个横排和竖列以及九宫格内无相同数字"这个条件的有效值。""" i, j = x//3, y//3grid = [m[i*3+r][j*3+c] for r in range(3) for c in range(3)]v = set([x for x in range(1,10)]) - set(grid) - set(m[x]) - \set(list(zip(*m))[y])    return vdef start_pos(m:"数独矩阵"):""" 功能:返回第一个空白格的位置坐标"""for x in range(9):for y in range(9):if m[x][y] == 0:return x, yreturn -1, -1  # 若数独已完成,则返回 -1, -1def try_sudoku(m:"数独矩阵", x:"空白格行数", y:"空白格列数"):""" 功能:试着填写数独 """    for v in value(m, x, y):if m[x][y] == 0:  # 判断是否为空格m[x][y] = vnext_x, next_y = get_next(m, x, y)            if next_y == -1: # 如果无下一个空白格print(m)return Trueelse:end = try_sudoku(m, next_x, next_y) # 递归if end:return Truem[x][y] = 0 # 在递归的过程中,如果数独没有解开,# 则回溯到上一个空白格    def sudoku(m):        x, y = start_pos(m)""" 解数独的一个结果try_sudoku(m, x, y)"""# 解数独的所有结果for v in value(m, x, y):        m[x][y] = vnext_x, next_y = get_next(m, x, y)try_sudoku(m, next_x, next_y)if __name__ == "__main__":m = [[6, 0, 0, 1, 0, 0, 7, 0, 8],[0, 0, 0, 8, 0, 0, 2, 0, 0],[2, 3, 8, 0, 5, 0, 1, 0, 0],[0, 0, 0, 0, 4, 0, 0, 9, 2],[0, 0, 4, 3, 0, 8, 6, 0, 0],[3, 7, 0, 0, 1, 0, 0, 0, 0],[0, 0, 3, 0, 7, 0, 5, 2, 6],[0, 0, 2, 0, 0, 4, 0, 0, 0],[9, 0, 7, 0, 0, 6, 0, 0, 4]]sudoku(m)"""
[[6, 9, 5, 1, 2, 3, 7, 4, 8], [7, 4, 1, 8, 6, 9, 2, 5, 3], [2, 3, 8, 4, 5, 7, 1, 6, 9], [8, 1, 6, 7, 4, 5, 3, 9, 2], [5, 2, 4, 3, 9, 8, 6, 7, 1], [3, 7, 9, 6, 1, 2, 4, 8, 5], [4, 8, 3, 9, 7, 1, 5, 2, 6], [1, 6, 2, 5, 8, 4, 9, 3, 7], [9, 5, 7, 2, 3, 6, 8, 1, 4]
]
"""

请转 B 站:

https://www.bilibili.com/video/av73750317


http://chatgpt.dhexx.cn/article/KBGLiXj2.shtml

相关文章

解数独c++

解数独 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) 数…

MATLAB 解数独

数独是一种较为常见的游戏,一般有4乘4、6乘6、9乘9几种,就像下面这种,本文也是主要求解此类数独。 此外还有一些奇形怪状的,如下图两种,均是不规则的,在此并不会涉及,但会在以后发布代码以及过程…

Leetcode 解数独

解数独 题目描述: 编写一个程序,通过填充空格来解决数独问题。一个数独的解法需遵循如下规则:数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。提示:…

再战leetcode (解数独)

37. 解数独 题目描述 回溯法 leetcode题解 代码 public class Test {public static void main(String[] args) {char[][] board {{5, 3, ., ., 7, ., ., ., .},{6, ., ., 1, 9, 5, ., ., .},{., 9, 8, ., ., ., ., 6, .},{8, ., ., ., 6, ., ., ., 3},{4, ., ., 8, ., 3, .…

回溯算法解数独问题(java版)

下面来详细讲一下如何用回溯算法来解数独问题。 下图是一个数独题,也是号称世界上最难的数独。当然了,对于计算机程序来说,只要算法是对的,难不难就不知道了,反正计算机又不累。回溯算法基本上就是穷举,解这…

014. 解数独

1.题目链接: 37. 解数独 2.解题思路: 2.1.题目要求: 暂时的理解就是,编写一个程序然后自动填完数独,填完返回(不用求解各种不同的数独组合) 填的时候,数字要满足的规则&#xff1…

回溯算法—解数独

什么是回溯法? 回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择&…

解数独--难的一批

1题目 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) 数…

解数独 — Python

文章目录 解数独1、程序简介示例:输入:输出:解释:提示: 2、程序代码3、运行结果 解数独 1、程序简介 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每…

【每日刷题】解数独

题目地址 https://leetcode-cn.com/problems/sudoku-solver/ 题目描述:解数独 编写一个程序,通过已填充的空格来解决数独问题。 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-…

算法学习:37. 解数独

解数独 题目链接:力扣题目链接 难度:困难 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫…

数独解题方法大全

数独这个数字解谜游戏,完全不必要用到算术!会用到的只是推理与逻辑。解题方法分两大类:直观法和候选数法。 直观法就是不需要任何辅助工具,从接到数独谜题的那一刻起就可以立即开始解题。绝不猜测。数独直观法解题技巧主要有&…

37.解数独

37. 解数独(难度:困难) 题目链接:https://leetcode-cn.com/problems/sudoku-solver/ 编写一个程序,通过已填充的空格来解决数独问题。 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次。数…

安装搜狗输入法成功,每次都折腾,记录一下这次的成功经验。

1:卸载fcitx sudo apt-get --purge fcitx* 2:清理系统内的无用的软件包 sudo apt-get --purge autoremove 3:到搜狗官网下载搜狗拼音输入法,选择你系统对应的软件包,我系统是64位的,所以我选择了amd64的 ht…

Ubuntu16.04 python2.7升级python3.5

原文地址:https://www.cnblogs.com/wmr95/p/7637077.html Ubuntu16.04 python2.7升级python3.5 正常情况下,你安装好ubuntu16.04版本之后,系统会自带 python2.7版本,如果需要下载新版本的python3.5,就需要进行更新。下…

(转)解决Ubuntu2.6.31-20内核更新问题:Unable to mount root fs on unknown-block(x,x)

原文章:http://hi.baidu.com/%D2%BB%B5%E3%C7%E7/blog/item/d3b0df30da10a115ebc4afa3.html Ubuntu2.6.31-20内核更新问题:Unable to mount root fs on unknown-block(x,x) WUBI装的ubuntu。在更新了最信的内核 2.6.31-20,启动时出现提示&a…

Git客户端的简单使用(注册-gt;应用)

参考文档: Ubuntu下git安装与使用:https://jingyan.baidu.com/article/dca1fa6f43c965f1a540524d.html Ubuntu下使用SSH KEY:https://jingyan.baidu.com/article/5bbb5a1bff545613eba17915.html 1. 通过apt源安装git命令行工具 这里不建…

windows10下的Ubuntu18.04的双系统的安装

windows下装Ubuntu18.04的双系统作为菜鸟,照着大神们的教程装了几遍,给大家分享一下流程。(默认装好Windows10) 1.【Win10上安装的软件】可在Win10上提前下载安装EasyBCD软件,用于之后开机时的双系统切换;…

[Linux 基础] -- Linux DRM (二) 基本概念和特性 - Rockchip

一、楔子 上篇文章中我们有讲过 DRM 是 Linux 下的图形渲染架构,用来管理显示输出、图层合成与更新、内存管理、分辨率设置等等功能的一套显示管理框架。应用程序可以直接操纵 drm 的 ioctl 或者是用 framebuffer 提供的接口进行显示相关操作。后来大家觉得这样太 …

ubuntu mysql5.7配置_MySQL5.7在Ubuntu上的安装、配置与使用

环境:html Ubuntu 1804 64位 python 待安装:MySQL5.7版本mysql 1、安装 一、下载mysql-apt的配置包,并安装 或者下载社区版本mysql5.7 https://www.cnblogs.com/metianzing/p/9050204.html sql 在安装的过程当中,会要求选择mysql版…