憋屈地看了一个星期的论文,实在是没一点意思。为了娱乐一下自己,兼受同学启发,我决定用python写一个数独游戏。从大二开始装了个ubuntu系统后,就发现了这个有趣的游戏。之后每次进入这个系统,非得先来几局数独;再到后来,为了玩数独,特意进了这个系统。喜欢这个自带的游戏的特点,界面简单,只做必要的错误提示,可以回溯,是我用过的最理想的数独游戏了,呵呵。至于我自己打算做一个数独游戏,纯粹是为了现学现用。自从开始学python以来,从来没有真正用它写过一段带有自己设计思想的代码,实是不该。何不就为自己做一个windows下也能玩的称心如意的数独呢?好了,取名就叫Eva's Sudoku~!不过话说回来,这篇文章的主题是:
总共有多少个数独?
这绝对不是一个简单的排列组合问题。关于这个问题,《编程之美》有过一个简单的推断介绍。根据里面找提供的一个网址,我找到了关于这个问题的详细解决方案[1]。现在让我们先做一些简单的规定:
1. 我们要求的是合法的数独总数,定为N
2. 对于数独中的9个块(block),分别命名如下:
3. 对于一个块(block),如果其内9个数字按如下方式排序,则称其为“标准型”:
总是可以通过替换使得一个块成为标准型的,这个过程叫做relabeling。这样的话,我们可以总是通过relabeling使B1成为标准型,对于一个B1是标准型的合法数独,它将可以通过relabeling得到9!个不一样的数独,因此,现在我们要求解的问题变成:
B1是标准型的合法数独有多少个?设该数为N1,我们有N=N1*9!。
好了,现在B1确定下来了,为了使数独合法,B2-B3总共有多少种可能呢?首先考虑B2的第一行,填写它的数字要么全部来自B1的第二行或第三行,要么是B1第二、三行的混合。B2-B3第一行的所有可能如下:
如果填写B2第一行的数字全部来自B1的第二行或第三行(我们称其为
pure的情况),合法的B2-B3的填法如下(图为填写B2第一行的数字全部来字B1的第二行):
每行内部都可以全排,因此总共有(3!)^6种可能,再加上填写B2第一行的数字全部来自B1第三行的情况,对于pure的情况,总共有2*(3!)^6种可能。
如果填写B2第一行的数字是B1第二、第三行的混合(总共有18种组合方式),列取其中一种来看(其中a,b,c各代表1,2,3中的某个数),在这种情况下,包括全排列,总共会有3*(3!)^6种排列情况:
因此,B2-B3的合法可能共有:
M1=2*(3!)^6+18*3*(3!)^6=56*(3!)^6=2612736
为了让问题快速得到一个接近的解,我们使用探索法来进一步分析:
我们从九宫格的每一个块出发,如果每个块都由1~9填充,不再有其他限制,则合法的解共有N0=(9!)^9;进一步加上限制,块行中每一行都由1~9填充,其合法的解共有M2=9!*M1,九宫格里共有3个块行,因此使三个块行都合法的解共有M=M2^3,满足块行限制的解的个数在满足块限制解的个数中所占的比例为k=M/N0,同理满足块列限制的解的个数在满足块限制解的个数中所占的比例也为k。假设以上两个比例相互独立(事实上它们并不完全独立),则同时满足块行解和块列解在满足块限制解中的比较约为k^2,因此同时满足块行列限制的解(即九宫格的解)的总数约为N0*k^2~6.657*10^21。该估计结果与精确结果6.671*10^21相差大约0.2%。
现在让我们进入精确结果的求解过程:
总的来说,求解的思路是暴力求解。设置两个loop循环,外循环穷举所有在B1为标准型的情况下B2-B3所有可能的解,内循环则在B2-B3的解的情况下穷举所有合法的数独的解。
1. 外循环
现在我们知道了B2-B3所有可能的解的个数了(M1=2612736),外循环将执行200多万次!这一想就让人觉得遥遥无期,有什么办法能够减少穷举的次数呢?选代表~!我们总是能够通过行列变换、交换元素等方法来使一个数独转变成另外一个数独,这样的话,当我们知道了第一个数独的解法,我们自然而然就知道了第二个数独的解法,第二个数独将与第一个数独有同样的解法个数(不知道你明白我的意思了没?)由此我们可能在所有B2-B3可能的解(M1=2612736种)的集合中定义等价关系,从而使等价集中的待完成的数独具有相等个数的解。
怎么从一个数独转换成另一个数独呢?前面我们使用了relabeling技术,但事实上除了这个以外,还有其他技术,如块交换,例如我们交换B2跟B3,相应的解只需要交换B5跟B6,B8跟B9,完成B2-B3的解的个数将与完成B3-B2的解的个数相等。我们还可以对B1、B2、B3进行全排,下面的B4~B9只需做相应的顺序调整。虽然这将使B1不再是标准型的,但是别忘了我们还可以通过relabeling技术使它成为标准型的。甚至我们还可以对块的列、行进行全排。这些技术将帮助我们选举出一些特定的代表来进入内循环,内循环算出的该代表的个数乘以该代表所在集合的个数,将是该集合的合法的数独解的个数。我决定用数学公式来表达这些绕口的事情:
现在我们的目标就是减少这个外循环的次数k。上面的分析我们知道,对B2、B3内的列进行全排列得到的解属于一个集合,对B2、B3进行交换得到的解也属于一个集合。因此我们选取的代表具有如下特点:
1. B2,B3的第一行是增序的;
2. B2的第一行的第一个数字小于B3第一行的第一个数字。
每个代表都存在2*(3!)^2种原始序列通过转换(lexicographical reduction)变成该代表,也就是说,解决了一个代表的解的个数,我们实际上解决了72种情况下的解的个数,现在我们把外循环k由2612736降到了36288(=2612736/72)。
上面的做法事实上并没有完全地利用全排列与relabeling技术。对于这36288种可能,我们可以对B1-B2-B3进行全排列,也可以对每个块中的三个列进行全排列,从而可以得到6^4=1296种不同的解,然后对B1进行relabeling,再对B2-B3进行lexicographical reduction从而使其成为一个代表,这将使原先的36288个代表进一步降到只剩下2051个代表(具体得出的结果是通过程序完成的);更进一步,可以对B1-B2-B3的行进行全排列,然后再将B1进行relabeling变换得到一个新的可能,最终,可以得到416个代表。
有时候交换特定元素并不改变数独其他元素的解,例如下面块行,完成他们的解的个数的相同的(因此它们也是等价的):
除了列6跟列9的元素对(8,9)之外,列4、7的(1,2)、列1、4的(1,4)、列2、9的(5,8)以及列3、6的(6,9)之间的交换也能达到同样的效果。
更近一步,除了一对一的交换,还有2对2的交换等等,如下图:
通过消除这些等价关系,最终我们只剩下了71个代表。通过解答这71个代表,最终发现其实只有44种完全不同的代表。也就是说,最终我们可以将外循环降到k=44。
2. 内循环
内循环的工作就是针对B1-B2-B3的44种代表中的每一个,穷举所有合法的完整数独,然后根据我们上面提供的公式,即可求出N1进而求出N。但是我们精益求精,对B2-B3的进行选举代表的办法也同样可以运用到B4、B7上,当然,由于它受到更多的限制,我们只限制B4、B7的第一列是递增的,这样我们可以通过行的全排列来求出其他的数独,这样的做法使内循环的速度提升了72倍。
通过对这44种代表的穷举,我们最终将得到N1=18383222420692992,进一步得到N=N1*9!=6670903752021072936960 ~ 6.671*10^21。
------------------------
[1]http://www.afjarvis.staff.shef.ac.uk/sudoku/
- 大小: 27.8 KB
- 大小: 43.7 KB
- 大小: 15.6 KB
- 大小: 15.3 KB
- 大小: 7.4 KB
- 大小: 13 KB
- 大小: 14.3 KB
- 大小: 14.4 KB
- 大小: 17.2 KB
- 大小: 16.9 KB
- 大小: 5.5 KB
分享到:
相关推荐
数独是一个常见的数字谜题,要求你用数字填充一个X9网格,使每个列,每一行,每一行的数字都包含所有数字,从 1到 9. 有多种方法可以解决这些问题,包括计算方法。 在这个项目中,简单的卷积神经网络具有无规则后处
首先,验证器会检查每一行是否有重复数字,如果在任何一行中发现有重复的数字,那么这个数独就不合法。接着,验证器会检查每一列,使用相同的方法来确认没有重复。最后,验证器会将大网格划分为9个3×3的小宫格,...
数独是一种广受欢迎的逻辑游戏,它通过填充1到9的数字到9x9的九宫格中,使得每一行、每一列以及每个3x3的小宫格内都包含这9个数字,且每个数字在各自的行、列和小宫格内只出现一次。这个项目“100个数独(Python语言...
数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏数独游戏...
数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码数独代码...
数独是一种广受欢迎的逻辑游戏,它通过填充一个9×9的网格,使得每一行、每一列以及每一个小的3×3宫格内的数字1到9都只出现一次,来达到解谜的目的。MATLAB作为一种强大的数值计算和编程环境,可以用来编写程序解决...
5. **数独变体**:除了标准数独,还有许多变体,如不规则数独(奇数数独、异形数独等)、对角数独、复杂数独等,每种变体都有其独特的规则和挑战。 6. **数独比赛**:了解数独竞赛的规则,包括时间限制、计分方式等...
总结来说,这个压缩包提供了一个基于C语言实现的高效数独填色算法,其性能强大,能在微秒级别内解决数独问题。通过研究“dd.c”文件,我们不仅可以了解到数独填色法的具体实现,还能从中学习到C语言编程技巧和算法...
数独是一种广受欢迎的逻辑推理游戏,它基于一个9x9的网格,被分为9个3x3的小宫格。每个宫格内需填入数字1到9,使得每行、每列以及每个小宫格内的数字都不重复。数独的解决方法多种多样,其中一种常见的是基于回溯的...
小巧的数独编辑器,现在可以编辑标准数独、宫格数独、锯齿数独、超级数独(或者叫窗口数独)、杀手数独、时钟数独等,并且数独的尺寸不限定为3x3,比如宫格数独可以编辑3x2及3x4等等的地图尺寸。压缩包中附带了若干...
最后,为了验证用户输入的合法性,程序会有一个校验函数,如`check_sudoku()`,用于检查当前的数独盘面是否有效。这个函数会遍历每个单元格,确认其所在的行、列和小九宫格内没有重复的数字。 总结来说,这个Python...
这个项目是针对Intel线程优化大赛设计的,意味着它着重于利用多核处理器的性能来提高数独问题的求解速度。 在并行计算领域,当一个任务被分解成多个子任务,这些子任务可以同时执行,从而缩短整体计算时间。对于...
数独计算器 数独游戏 数独秒算 本数独游戏 采用分为闯关模式和 随机模式,随机模式中的题库更多,闯关模式会随着 关数的增加而越来越难。...另外还有个数独计算器,妙算数独。 修复了上次数独计算器的2个BUG
功能描述 winform数独C#的数独游戏 ...然后从完整无缺的数独结果中,随机取其中的若干(限定范围内的随机个数)个数字作为数独题目即可。取出的数字的数量越多,题目越容易,反之越难。
在实现数独时,我们可以创建一个9x9的二维数组来表示数独盘面,每个单元格可以是一个数字控件或指示器,允许玩家输入和查看数字。在前面板上,这些控件将排列成9x9的矩阵,用户可以通过鼠标点击来选择和修改单元格的...
数独游戏的目标是在9×9的网格中填入1到9的数字,使得每一行、每一列以及每个3×3的小宫格内数字都不重复。这个游戏对提升逻辑思维、空间推理和专注力有很大帮助。 在Mars老师的数独游戏教程中,可能涉及到了如何...
杀手数独游戏的规则与经典数独相同,即每行、每列、每个小方框中都不能重复出现同一个数字(1-9)。但与经典数独不同的是,杀手数独中还存在一些特殊的约束条件,即一些小方框中的数字必须满足一定的条件,例如:...
【数独】入门练习题(四宫)-200道,pdf 六宫数独300题.pdf 数独《中级》练习题(九宫)含案-100道.pdf 数独《中级》练习题(九宫)含答案-100道.pdf 数独入门-儿童数独游戏第1级-唯一法4X4.pdf 数独入门-儿童数独游戏第1级...
而"数独终结者"是一款基于C++编程语言,利用Microsoft Foundation Classes (MFC)库开发的标准数独计算器,旨在为数独爱好者提供一个自动化解题工具,同时也为编程学习者提供了优秀的参考实例。下面我们将深入探讨该...
数独游戏是一款经典的逻辑谜题,它通过填充一个9×9的网格,使得每一行、每一列以及每一个小的3×3宫格内的数字都从1到9不重复出现,以此来锻炼玩家的逻辑思维和推理能力。VB(Visual Basic)是一种由微软公司开发的...